Spring MVC基础整理- 请求参数接收处理、响应、拦截器、上传文件、拦截器、异常处理基础整理
大家如有疑问和讨论及时留言
一、spring MVC请求原理图
1.1DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
1.2 HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的 映射方式,例如:配置文件方式,实现接口方式,注解方式等。
1.3 Handler:处理器 (自己定义的Controller处理单元)
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由 Handler 对具体的用户请求进行处理。
1.4 HandlAdapter:处理器适配器
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行
二、Controller 中请求参数 设置
2.1 设置 params 必须包含参数如【password】和【username!=root】
@RequestMapping( value = "/***" ,params = {"username!=root","password"})
2.2 设置请求headers
@RequestMapping( value = "/***",headers = {"Accept-Encoding=gzip, deflate"})
2.3 请求参数 转换成Action接收对象处理说明
实体类 后续传输参数都用该实体类
@AllArgsConstructor @NoArgsConstructor @Data public class Person implements Serializable { private String pname; private String page; private String gender; private String[] hobby; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date birthdate; private List<Pet> pets; private Map<String,Pet> petMap; }
前端请求 content-type 默认 及 application/www-form-urlencoded
import java.util.Arrays; /** * @Author: Ma HaiYang * @Description: MircoMessage:Mark_7001 */ @RestController public class ReceiveDataController { /* * 使用POJO接收参数时,注意事项 * 提交的参数名必须和POJO的属性名保持一致 * springmvc底层通过反射给参数列表的属性赋值 * 通过set方法设置属性值的,不是直接通过操作属性 * POJO的属性一定要有set方法,要不然就会接收失败 * */ @RequestMapping("/getDataByPojo") public String getDataByPojo(Person p){ System.out.println(p); return "success"; } }
2.4 日期类型参数接收
接收 string 2022-07-02 接收成 Date birDate 使用注解 @DateTimeFormat(pattern = "yyyy-MM-dd") ,可用在实体对象字段上 @RequestMapping("testDate") public String getTestDate(@DateTimeFormat(pattern = "yyyy-MM-dd") Date birDate){
2.4.1 通用转换日期
@Component public class StringToDateConverter implements Converter<String, Date> { Private SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd"); @Override public Date convert(String source) { Date date =null; try { date = dateFormat.parse(source); } catch (Exception e) { throw new RuntimeException("日期转换异常"); } return date; } }
2.5 Person 有List<pet> 集合, hobby数组、petMap
Controller接收
@RequestMapping("/getDataByPojo") public String getDataByPojo(Person p){ System.out.println(p); System.out.println(p.getPets()); return "success"; }
form表单请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="getDataByPojo" method="post">
<p>姓名<input type="text" name="pname"></p>
<p>年龄<input type="text" name="page"></p>
<p>性别:
<input type="radio" name="gender" value="1" >男
<input type="radio" name="gender" value="0" >女
</p>
<p>爱好
<input type="checkbox" name="hobby" value="1"> 篮球
<input type="checkbox" name="hobby" value="2"> 足球
<input type="checkbox" name="hobby" value="3"> 羽毛球
</p>生日
<p>
<input type="text" name="birthdate">
</p>
宠物List:
<p>
宠物1: 名字:<input type="text" name="pets[0].petName" >类型:<input type="text" name="pets[0].petType">
</p>
<p>
宠物2: 名字:<input type="text" name="pets[1].petName" >类型:<input type="text" name="pets[1].petType">
</p>
宠物Map:
<p>
宠物1: 名字:<input type="text" name="petMap['a'].petName" >类型:<input type="text" name="petMap['a'].petType">
</p>
<p>
宠物2: 名字:<input type="text" name="petMap['b'].petName" >类型:<input type="text" name="petMap['b'].petType">
</p>
<input type="submit">
</form>
</body>
</html>
2.6 ResponseBody 和RestController
@ResponseBody
* 1方法的返回值不在作为界面跳转依据,而已直接作为返回的数据
· * 2将方法的返回的数据自动使用ObjectMapper转换为JSON
@RestController
相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就 不能返回jsp,html页面,视图解析器无法解析jsp,html页面
2.7 Controller 响应处理
@Controller 返回页面重定向
2、使用forward关键字完成响应 return "/forwardPage.jsp"; 3、使用View视图转发和重定向 · // 重定向 · view=new RedirectView(req.getContextPath()+"/redirectPage.jsp"); · return view; 4、使用ModelAndView转发重定向 · ModelAndView mv=new ModelAndView(); · // 请求转发 · //mv.setViewName("forward:/forwardPage.jsp"); · //mv.setView(new InternalResourceView("/forwardPage.jsp")); · // 重定向 · //mv.setViewName("redirect:/redirectPage.jsp"); · mv.setView(new RedirectView(req.getContextPath()+"/redirectPage.jsp")); · return mv;
2.8文件上传
pom 节点
· <!--文件上传依赖--> · <dependency> · <groupId>commons-fileupload</groupId> · <artifactId>commons-fileupload</artifactId> · <version>1.4</version> · </dependency> · · · <dependency> · <groupId>commons-io</groupId> · <artifactId>commons-io</artifactId> · <version>2.8.0</version> · </dependency>
SpringMvc需要、springboot 应该不需要
package com.msb.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; /** * @Author: Ma HaiYang * @Description: MircoMessage:Mark_7001 */ @Controller public class FileUploadController { @ResponseBody @RequestMapping("fileUpload.do") public String fileUpload(MultipartFile headPhoto) throws IOException { // 指定文件存储目录 File dir = new File("d:/imgs"); // 获取文件名 String originalFilename = headPhoto.getOriginalFilename(); // 文件存储位置 File file =new File(dir,originalFilename); // 文件保存 headPhoto.transferTo(file); return "OK"; } }
获取站点下绝对路径需要设置 idea 环境变量 workdirectory为resource对应目录
HttpServletRequest req;
String realPath=req.getServletContext.getRealPath(“upload”);
2.9单独准备文件存储服务器
1、创建新Tomcat 站点 webaapp 新建upload目录
2、远程服务器中设置非只读
三、过滤器和拦截器
拦截器 说明
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
1.通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。
2.通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。
拦截器和过滤器的区别
1拦截器SpringMVC的,而过滤器是servlet的。
2拦截器不依赖与servlet容器,由spring容器初始化,过滤器依赖与servlet容器,由servlet容器初始化。
3拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
4拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
5在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
6拦截器可以获取IOC容器中的各个bean,而过滤器就不太方便,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
拦截器内容详解
3.1、preHandle方法
具体作用
如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去 进行处理,则返回 true。 。 如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
/** * * @param request 请求对象 * @param response 响应对象 * @param handler 目标要调用的Handler * @return 返回true放行,返回false拦截 * @throws Exception */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { /*在请求到达我们定义的handler之前工作的*/ System.out.println("MyInterceptor preHandle"); /*设置请求和响应的乱码 */ /* request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8");*/ // 判断是否登录 /*User user =(User) request.getSession().getAttribute("user"); if(null == user) response.sendRedirect("index.jsp"); 可以返回response 设置body 返回 json 数据 return false;*/ // 用户权限控制 return true; }
3.2、postHandle方法
执行时机
在进行数据处理和做出响应之间进行这个方法的调用
如何调用
在拦截器链内所有拦截器返成功调用
具体作用
在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,
在该方法中对用户请求 request域数据进行处理。
/** * * @param request * @param response * @param handler * @param modelAndView controller响应的结果,视图和数据 * @throws Exception */ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyInterceptor postHandle"); /*控制数据*/ /*Map<String, Object> map = modelAndView.getModel(); String msg = (String)map.get("msg"); String newMsg = msg.replaceAll("脏话", "**"); map.put("msg", newMsg);*/ /*控制视图*/ /*modelAndView.setViewName("/testDemo1.jsp");*/ }
3.3、afterCompletion方法
执行时机
在进行页面渲染的时候执行
如何调用
按拦截器定义逆序调用
具体作用
在DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
/** * 无论controller是否出现异常,都会执行的方法 * 一般来说都做一些资源释放工作 * @param request * @param response * @param handler * @param ex * @throws Exception */ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { /*页面渲染完毕,但是还没有给浏览器响应数据的时候*/ System.out.println("MyInterceptor afterCompletion"); System.out.println(ex); }
3.3、自定义静态资源映射
https://blog.csdn.net/qq_44196212/article/details/124242026?spm=1001.2014.3001.5502
四、
用@ExceptionHandler注解处理异常
缺点:只能处理当前Controller中的异常。 · @Controller · public class ControllerDemo1 { · @RequestMapping("test1.action") · public String test1(){ · int i = 1/0; · return "success.jsp"; · } · @ExceptionHandler(value ={ArithmeticException.class,NullPointerException.class} ) · public ModelAndView handelException(){ · ModelAndView mv =new ModelAndView(); · mv.setViewName("error1.jsp"); · return mv; · } · }
4.2 使用:@ControllerAdvice+@ExceptionHandler
此处优先级低于局部异常处理器
/** * @Author: Ma HaiYang * @Description: MircoMessage:Mark_7001 */ @ControllerAdvice public class GloableExceptionHandler1 { @ExceptionHandler(value ={ArithmeticException.class,NullPointerException.class} ) public ModelAndView handelException(){ ModelAndView mv =new ModelAndView(); mv.setViewName("error1.jsp"); return mv; } }
全局异常
1. * 全局异常 2. 3. * HandlerExceptionResolve 4. 5. */ 6. 7. @Configuration 8. 9. public class GloableException3 implements HandlerExceptionResolver { 10. 11. @Override 12. 13. public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { 14. 15. ModelAndView mv = new ModelAndView();16. 17. if(e instanceof NullPointerException){18. 19. mv.setViewName("error1");20. 21. } 22. 23. if(e instanceof ArithmeticException){24. 25. mv.setViewName("error2"); 26. 27. }29. mv.addObject("msg",e);31. return mv;33. }}