springmvc

加载顺序

根据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的配置当中,0的含义是:

            (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)->将得到视图对象返回给用户

如下图所示:

SpringMVC运行原理

异常

  1. 异常处理方式一. @ExceptionHandler
  2. 异常处理方式二. 实现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();
    }
 
}
  1. 异常处理方式三. @ControllerAdvice+@ExceptionHandler
  2. 三种方式比较说明(强烈推荐各位看一下,我觉得自己总结的比较多,嘿嘿,不对之处请指出,点我快速前往!)

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 map)

https://zhuanlan.zhihu.com/p/139162484

类型转换

springmvc参数类型转换三种方式

你可能感兴趣的:(springmvc)