创建一个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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://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 {@Overridepublic 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://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参数
@Controllerpublic 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,取个名字,前段就用这个取得名字进行传参,前端传值最好都要加上这个,约定好习惯
@Controllerpublic 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@NoArgsConstructorpublic class User {private int id;private String name;private int age;}
@Controllerpublic class RestFulController {@GetMapping("/add/test1")public String test1(User user){System.out.println(user);return "test";}}
RESTful风格传参
@Controllerpublic 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……
@Controllerpublic 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";}}
简便方式
@Controllerpublic 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}")//每个请求方式都有一个对应的Mappingpublic 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
```javapackage 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://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 {@Autowiredprivate UploadService uploadService;@PostMapping("")public ResponseResult upload(MultipartFile file){return uploadService.upload(file);}}
这个文件对象里面可以转换成流和字节数组等,方便操作。
前端上传请求头里面得包含Content-Type:multipart/form-data;
重定向和转发
@Controllerpublic 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttps://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>



