创建一个SpringMVC项目
1. 导入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
2. 项目目录
3. 配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置DispatchServlet:这个是SpringMVC的核心,请求分发器,前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatcherServlet要绑定Spring的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别:1.服务器一启动它就自己启动-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--
所有的请求都会去走上面的servlet
在SpringMVC中 /和/*的区别
/:只会匹配所有的请求,不会去匹配jsp页面
/*:匹配所有的请求,包括jsp
本来访问的是hello请求,springmvc会主动追加前缀和后缀,比如变成index/hello.jsp,
如果设置了/*,在 访问请求hello.jsp,然后又要被springmvc追加一个前后缀,hello.jsp.jsp
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4. 配置Spring配置文件springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--处理器映射器-->
<bean class ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器-->
<bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--加上前后缀,就只用访问名字就行了,会主动拼接上前后缀的-->
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--
下面的就是自己配置的映射路径了
当访问/hello时,就去找HelloController控制器
-->
<bean id="/hello" class="com.lyd.controller.HelloController"/>
</beans>
5. 创建控制器Controller
package com.lyd.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//需要实现Controller接口,实现了接口,它就是控制器了
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv =new ModelAndView();
//业务代码
String result ="HelloSpringMVC";
mv.addObject("msg",result);
//视图跳转
mv.setViewName("test");
return mv;
}
}
6. 启动tomcat运行项目
看这里
Tomcat
在浏览器上,就能访问到结果了。jsp里面我只写了一个显示msg值
7. 可能发生404错误
有可能访问/hello出现404,有种可能是没有生成对应的lib,自己手动去添加
打开项目结构
右键lib目录,最后全选加进去
使用注解开发SpringMVC
目录结构
升级springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--自动扫描包,让指定包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.lyd.controller"/>
<!--让SpringMVC不处理静态资源 .css .js .html .mp3 .mp4等-->
<mvc:default-servlet-handler/>
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理
而annotation-driven配置帮助我们自动完成上述两个实例的注入
-->
<mvc:annotation-driven/>
<!--视图解析器-->
<bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--加上前后缀,就只用访问名字就行了,会主动拼接上前后缀的-->
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
升级Controller注解写法
package com.lyd.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
//用注解就是把他变成了一个控制器了,这个是之前Spring文章里面讲到的衍生组件
//被这个注解的类中的所有方法,如果返回值是String,并且有具体的页面可以跳转,那么就会被视图解析器解析
@Controller
//@RequestMapping可以写在类上面,也可以写在方法上
//写在类上表示通过这个路径就能映射到这个控制器,就不用向之前那样在spring配置文件里面一直加bean映射
@RequestMapping("hello")
public class HelloController {
//方法上的RequestMapping直接通过子路径返回到对应的视图
//这里的访问路径是 localhost:8080/hello/h1
//不写类上面的RequestMapping,这里的访问路径是localhost:8080/h1
@RequestMapping("/h1")
public String hello(Model model){
//封装数据
model.addAttribute("msg","这是用注解实现的SpringMVC");
//这个return的结果会被视图解析器处理
return "hello";
}
//路径 /hello/index
@RequestMapping("index")
public String index(Model model){
model.addAttribute("msg","这个是index.jsp页面");
return "index";
}
}
传参
普通传参
默认传参
写一个控制器,test.jsp页面就显示这个msg参数
@Controller
public class RestFulController {
@RequestMapping("/add/test1")
public String test1(int a,int b , Model model){
int res=a+b;
model.addAttribute("msg","结果为"+res);
return "test";
}
}
test1()方法的参数a,b就是请求要传的参数,前端参数名字不能错,要和java代码里面的参数一样。
@RequestParam
在参数前指定@RequestParam,取个名字,前段就用这个取得名字进行传参,前端传值最好都要加上这个,约定好习惯
@Controller
public class RestFulController {
@GetMapping("/add/test1")
public String test1(@RequestParam("a") int a, @RequestParam("a") int b , Model model){
int res=a+b;
model.addAttribute("msg","结果为"+res);
return "test";
}
}
传参是一个对象
前端的参数名要和对象的属性名一致,如果不一致,要用@RequestParam
package com.lyd.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
@Controller
public class RestFulController {
@GetMapping("/add/test1")
public String test1(User user){
System.out.println(user);
return "test";
}
}
RESTful风格传参
@Controller
public class RestFulController {
//用PathVariable注解放在参数前面,作为路径变量
//这样就可以通过URL路径传参了,要在RequestMapping里面的路径上用{参数名},用/隔开参数与路径
@RequestMapping("/add/test1/{a}/{b}")
public String test1(@PathVariable int a, @PathVariable int b , Model model){
int res=a+b;
model.addAttribute("msg","结果为"+res);
return "test";
}
}
请求方法Get,Post……
@Controller
public class RestFulController {
//RequestMapping注解有多个参数,method参数可以指定求情方法
@RequestMapping(name="/add/test1/{a}/{b}",method = RequestMethod.POST)
public String test1(@PathVariable int a, @PathVariable int b , Model model){
int res=a+b;
model.addAttribute("msg","结果为"+res);
return "test";
}
}
简便方式
@Controller
public class RestFulController {
//@RequestMapping(name="/add/test1/{a}/{b}",method = RequestMethod.POST)
//可以用下面这种拓展注解进行不同方法的请求
@GetMapping("/add/test1/{a}/{b}")
//@PostMapping("/add/test1/{a}/{b}")
//@DeleteMapping("/add/test1/{a}/{b}")
//每个请求方式都有一个对应的Mapping
public String test1(@PathVariable int a, @PathVariable int b , Model model){
int res=a+b;
model.addAttribute("msg","结果为"+res);
return "test";
}
}
返回参数给前端
如上代码,在方法形参加上一个参数,用这个参数就能携带东西到前端了,有如下三种类型可以选择
- Model:精简版本,只有几个方法适合用于存储数据
- ModelMap:继承了LinkedMap,除了实现自身的一些方法,同样的继承了LinkedMap的方法和特性
- ModelAndView:可以在存储数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转
Json传参
接收json
RequestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容。
RequestBody的作用是将前端传来的json格式的数据转为自己定义好的javabean对象,需要注意的是传入数据的属性名称要和后端javabean中定义的一致。大小写都要一致@RequestMapping("/addbook")
//加上@RequestBody注解表示,前端传过来的json值映射成这个对象,json值得键要和对象的属性名一致,大小写都要一致
public int add(@RequestBody BookList booklist){
return bookserv.addBook(booklist);
}
Jackson
导依赖 ```xmlcom.fasterxml.jackson.core jackson-databind 2.13.1
```java
package com.lyd.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lyd.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController //这个注解表示这个类里面的所有方法都不走视图解析器,会全部返回字符串
//@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/ujson")
//@ResponseBody //加了这个注解,这个方法就不会走视图解析器,会直接返回一个字符串
public String json1() throws JsonProcessingException {
User user =new User(1,"张三",34);
//使用Jackson里面的方法把Java对象转换成json字符串
ObjectMapper objm =new ObjectMapper();
String jsonstr = objm.writeValueAsString(user);
return jsonstr;
}
}
Fastjson
导依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.80</version>
</dependency>
@RestController //这个注解表示这个类里面的所有方法藕不走视图解析器,会全部返回一个字符串
@RequestMapping("/user")
public class UserController {
@RequestMapping("/ujson")
public String json1() throws JsonProcessingException {
User user =new User(1,"张三",34);
//JSON.parseXxxxx 此类方法就是把前段发过来的东西解析成xxx的
return JSON.toJSONString(user);
}
}
Json乱码问题
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--自动扫描包,让指定包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.lyd.controller"/>
<!--让SpringMVC不处理静态资源 .css .js .html .mp3 .mp4等-->
<mvc:default-servlet-handler/>
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理
而annotation-driven配置帮助我们自动完成上述两个实例的注入
-->
<!--配置JSON乱码问题-->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--视图解析器-->
<bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--加上前后缀,就只用访问名字就行了,会主动拼接上前后缀的-->
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
上传文件
用MultipartFile
类型接收文件,前端传的文件名要和file对应,当然也可以写@RequestParam
@RestController
@RequestMapping("/upload")
public class UploadController {
@Autowired
private UploadService uploadService;
@PostMapping("")
public ResponseResult upload(MultipartFile file){
return uploadService.upload(file);
}
}
这个文件对象里面可以转换成流和字节数组等,方便操作。
前端上传请求头里面得包含Content-Type:multipart/form-data;
重定向和转发
@Controller
public class RestFulController {
@GetMapping("/add/test1/{a}/{b}")
public String test1(@PathVariable int a, @PathVariable int b , Model model){
int res=a+b;
model.addAttribute("msg","结果为"+res);
//默认转发
//return "test";
//重定向
return "redirect:/index.jsp";
}
}
乱码问题
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置DispatchServlet:这个是SpringMVC的核心,请求分发器,前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatcherServlet要绑定Spring的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别:1.服务器一启动它就自己启动-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--
所有的请求都会去走上面的servlet
在SpringMVC中 /和/*的区别
/:只会匹配所有的请求,不会去匹配jsp页面
/*:匹配所有的请求,包括jsp
本来访问的是hello请求,springmvc会主动追加前缀和后缀,比如变成index/hello.jsp,
如果设置了/*,在 访问请求hello.jsp,然后又要被springmvc追加一个前后缀,hello.jsp.jsp
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置SpingMVC的乱码过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
拦截器
拦截请求,当请求一个xxx地址时,如果配置了拦截器,请求会先被拦截器拦截,拦截器判断这个请求要不要通过,不通过的话,请求都到不了控制器。拦截器通过了才会到控制器。
新建一个java文件作为拦截器。
拦截器有HttpServletRequest和HttpServletResponse,可以做的事很多,比如登陆,在拦截器里面发现没有sessionid,就通过HttpServletResponse重定向到登陆页面
package com.lyd.config;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//需要实现HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
//return true;执行下一个拦截器,放行
//return false;不执行下一个拦截器
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("==============拦截前============");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("==============拦截后============");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("==============清理============");
}
}
配置spring配置里面的mvc拦截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--1.注解驱动,配置JSON乱码问题-->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--2.静态资源过滤-->
<mvc:default-servlet-handler/>
<!--3.扫描包-->
<context:component-scan base-package="com.lyd.*"/>
<!--4.视图解析器-->
<bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--加上前后缀,就只用访问名字就行了,会主动拼接上前后缀的-->
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--5.拦截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--包括这个请求下面的所有的请求-->
<mvc:mapping path="/**"/>
<!--配置写的拦截器-->
<bean class="com.lyd.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>