加载顺序
根据Servlet规范,各组件的加载 顺序如下:
顺序就是:context-param -> listener -> filter -> servlet
对于某类配置节而言,与它们出现的顺序是有关的。
以 filter 为例,web.xml 中当然可以定义多个 filter,与 filter 相关的一个配置节是 filter-mapping,这里一定要注意,对于拥有相同 filter-name 的 filter 和 filter-mapping 配置节而言,filter-mapping 必须出现在 filter 之后,否则当解析到 filter-mapping 时,它所对应的 filter-name 还未定义。web Tomcat启动时初始化每个 filter 时,是按照 filter 配置节出现的顺序来初始化的,当请求资源匹配多个 filter-mapping 时,filter 拦截资源是按照 filter-mapping 配置节出现的顺序来依次调用 doFilter() 方法的。
Servlet的mapping 同 filter 类似。
关于Servlet的load-on-startup:
load-on-startup 元素在web应用启动的时候指定了servlet被加载的顺序,它的值必须是一个整数。如果它的值是一个负整数或是这个元素不存在,那么Tomcat会在该servlet被调用的时候,加载这个servlet 。如果值是正整数或零,Tomcat在加载配置的时候就加载并初始化这个servlet,Tomcat必须保证值小的先被加载。如果值相等,Tomcat可以自动选择先加载谁。
在servlet的配置当中,
(1)标记Tomcat是否在启动的时候就加载这个servlet。
(2)当值为0或者大于0时,表示Tomcat在应用启动时就加载这个servlet;
(3)当是一个负数时或者没有指定时,则指示Tomcat在该servlet被选择时才加载。
(4)正数的值越小,启动该servlet的优先级越高。
web.xml中 listener、filter、servlet等 加载顺序
springmvc的listener、 filter、servlet 加载顺序及其详解
https://github.com/seaswalker/spring-analysis/blob/master/note/spring-mvc.md#%E5%88%9D%E5%A7%8B%E5%8C%96
配置文件
org.springframework.web.context.ContextLoaderListener
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring/springmvc-servlet.xml
1
springmvc
/
SpringMVC 工作原理(重要)
简单来说:
客户端发送请求-> 前端控制器 DispatcherServlet 接受客户端请求 -> 找到处理器映射 HandlerMapping 解析请求对应的 Handler-> HandlerAdapter 会根据 Handler 来调用真正的处理器开处理请求,并处理相应的业务逻辑 -> 处理器返回一个模型视图 ModelAndView -> 视图解析器进行解析 -> 返回一个视图对象->前端控制器 DispatcherServlet 渲染数据(Moder)->将得到视图对象返回给用户
如下图所示:
异常
- 异常处理方式一. @ExceptionHandler
- 异常处理方式二. 实现HandlerExceptionResolver接口
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("发生全局异常!");
ModelMap mmp=new ModelMap();
mmp.addAttribute("ex",ex.getMessage());
response.addHeader("Content-Type","application/json;charset=UTF-8");
try {
new ObjectMapper().writeValue(response.getWriter(),ex.getMessage());
response.getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
return new ModelAndView();
}
}
- 异常处理方式三. @ControllerAdvice+@ExceptionHandler
- 三种方式比较说明(强烈推荐各位看一下,我觉得自己总结的比较多,嘿嘿,不对之处请指出,点我快速前往!)
https://www.cnblogs.com/lvbinbin2yujie/p/10574812.html
HandlerInterceptor
拦截器,用来干嘛呢,就比如你需要检测用户的权限,或者把请求信息记录到日志等等,也就是说需要在用户请求前后执行的一些行为
首先在 Spring MVC 中是有两种机制,第一种就是实现 HandlerInterceptor接口,还有一种就是实现 Spring 的 WebRequestInterceptor 接口
数据绑定和参数绑定
https://www.cnblogs.com/linjiaxin/p/7753374.html
https://zhuanlan.zhihu.com/p/139162484
https://www.jianshu.com/p/bf1ff5b31918
在spring早期版本使用PropertyEditor(只能转java对象),后期使用converter(可转换任意类型)
public class User {
private String id;
private String name;
......补充其 get set toString 方法
}
http://localhost:8080/objectType.do?id=001&name=Steven
public class UserDetails {
private Integer age;
private String address;
......补充其 get set toString 方法
}
public class User {
private String id;
private String name;
private UserDetails userDetails;
......补充其 get set toString 方法
}
http://localhost:8080/objectType.do?id=1&name=Steven&userDetails.age=20&userDetails.address=BeiJing
对于引入的对象成员复赋值,格式就例如:userDetails.address=xxxxx
这里地址我没用中文,是因为我是直接返回的,没经过编码的处理,不然会显示 ? ?
同属性对象参数绑定
如果我们想要直接接收两个对象,有时候免不了有相同的成员,例如我们的 User 和 Student 类中均含有
Integer id 、String name 两个成员,我们试着请求一下
http://localhost:8080/objectType2.do?id=8&name=Steven
@RequestMapping("objectType2.do")
@ResponseBody
public String objectType2(User user, Student student) {
return user.toString() + " " + student.toString();
}
返回结果:User{id='8', name='Steven'} Student{id='8', name='Steven'}
可以看到,两个对象的值都被赋上了,但是,大部分情况下,不同的对象的值一般都是不同的,为此,我们还有解决办法
@InitBinder 注解可以帮助我们分开绑定,下面的代码也就是说分别给 user、student 指定一个前缀
http://localhost:8080/objectType2.do?user.id=1&name=Steven&stu.id=002
@InitBinder("user")
public void initUser(WebDataBinder binder) {
binder.setFieldDefaultPrefix("user.");
}
@InitBinder("student")
public void initStudent(WebDataBinder binder) {
binder.setFieldDefaultPrefix("stu.");
}
当发起这样一个请求后,我们分别指定了 user 和 student 的 id 值,而 name 则是同样的 Steven
返回结果:User{id='1', name='Steven', userDetails=null} Student{id='2', name='Steven'}
// http://localhost:8080/springmvc/objecttype3.do?people.name=Tom&user.name=Lucy
// http://localhost:8080/springmvc/objecttype3.do?people.name=Tom
// http://localhost:8080/springmvc/objecttype3.do?name=Tom
@RequestMapping(value = "objecttype3.do")
@ResponseBody
public String objecttype3(People people, User user) {
return "people=" + people + ",user=" + user;
}
@InitBinder("people")
public void initPeople(WebDataBinder binder) {
binder.setFieldDefaultPrefix("people.");
}
@InitBinder("user")
public void initUser(WebDataBinder binder) {
binder.setFieldDefaultPrefix("user.");
}
/**
* 解决前端传递的日期参数验证异常
*
* @param binder
* @author hzj
*/
@InitBinder({"param", "date"})//指定校验参数
protected void initBinder(WebDataBinder binder) {
// binder.setDisallowedFields("name"); // 不绑定name属性
binder.registerCustomEditor(String.class, new StringTrimmerEditor());
// 此处使用Spring内置的CustomDateEditor
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
@ResponseBody
@GetMapping("/initbinder")
public String testInitBinder(String param, Date date) {
return param + ":" + date;
}
(三) 数组类型参数绑定
http://localhost:8080/arrayType.do?nickname=Jack&nickname=Steven&nickname=Tom
@RequestMapping("arrayType.do")
@ResponseBody
public String arrayType(String[] nickname) {
StringBuilder sb = new StringBuilder();
for (String s : nickname) {
sb.append(s).append(", ");
}
return sb.toString();
}
返回结果:Jack, Steven, Tom,
集合类型参数绑定List 类型
http://localhost:8080/listType.do?users[0].id=1&users[0].name=Jack&users[1].id=2&users[1].name=Marry
@RequestMapping("listType.do")
@ResponseBody
public String listType(UserList userList) {
return userList.toString();
}
http://localhost:8080/listType.do?users%5B0%5D.id=1&users%5B0%5D.name=Jack&users%5B1%5D.id=2&users%5B1%5D.name=Marry
Tomcat高的版本地址中不能使用“[”和“]” ,我们可以将其换成对应的16进制,即 “[” 换成 %5B,“]” 换成 %5D
或者直接用 post 请求也是可以的哈
Map 类型
http://localhost:8080/mapType.do?users['userA'].id=1&users['userA'].name=Jack&users['userB'].id=2&users['userB'].name=Tom
public String mapType(UserMap userMap)
json
data:'{"id":"37","name":"张三"}',
public Admin ajaxType1(@RequestBody Admin admin)
public Admin ajaxType3(@RequestBody Map
https://zhuanlan.zhihu.com/p/139162484
类型转换
springmvc参数类型转换三种方式