SpringMVC体系

一  SpringMVC的基本概念:

三层架构:

表现层

业务层

数据层

SpringMVC体系_第1张图片

mvc:

M:Model数据模型,封装数据的javabean

V:View视图,前端展示的一些东西(jsp.html)

C:Controller控制器,处理交互的调度,SpringMVC就属于这一层

SpringMVC体系_第2张图片SpringMVC:SpringMVC是一种基于Java实现的轻量级控制层(web)框架!

二 SpringMVC的请求的执行流程:

回顾Servlet的执行流程,web.xml文件加载:

SpringMVC体系_第3张图片

 SpringMVC的web.xml配置:一个出列乱码,在Servlet的配置上其实都一样,使用了Spring定义的Servlet进行了统一的拦截,这个配置谁来写都是一样的,用到直直复制即可!




    
    
        CharacterEncodingFilter
        org.springframework.web.filter.CharacterEncodingFilter
        
            encoding
            UTF-8
        
    
    
        CharacterEncodingFilter
        /*
    

    
        DispatcherServlet
        org.springframework.web.servlet.DispatcherServlet
        
            contextConfigLocation
            classpath*:spring-mvc.xml.bak
        
    
    
        DispatcherServlet
        /
    


 SpringMVC的核心配置文件:



<!--扫描包含@Controllerz注解的类,其实就是只想扫描包含SpringMVC层的注解-->
    
        
    


    




    
    

SpringMVC启动服务时候的执行流程!

  • 服务器启动

    1. 加载web.xml中DispatcherServlet

    2. 读取spring-mvc.xml中的配置,加载所有扫描包中所有标记为bean的类

    3. 读取bean中方法上方标注@RequestMapping的内容

  • 处理请求

    1. DispatcherServlet配置拦截所有请求 /

    2. 使用请求路径与所有加载的@RequestMapping的内容进行比对

    3. 执行对应的方法

    4. 根据方法的返回值在webapp目录中查找对应的页面并展示!

 SpringMVC请求到响应的完整过程:

SpringMVC体系_第4张图片

 使用注解代替Web.xml文件和SpringMVC的核心配置文件:(谁写都一样,用到来粘贴即可)

替换web.xml文件配置(纯注解粘贴即可)

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    //创建Servlet容器时,使用注解的方式加载SPRINGMVC配置类中的信息,并加载成WEB专用的ApplicationContext对象
    //该对象放入了ServletContext范围,后期在整个WEB容器中可以随时获取调用
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        //加载SpringMVC的配置类
        ctx.register(SpringMVCConfiguration.class);
        return ctx;
    }

    //注解配置映射地址方式,服务于SpringMVC的核心控制器DispatcherServlet
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    //乱码处理作为过滤器,在servlet容器启动时进行配置
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        CharacterEncodingFilter cef = new CharacterEncodingFilter();
        cef.setEncoding("UTF-8");
        FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter", cef);
        registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST,DispatcherType.FORWARD,DispatcherType.INCLUDE),false,"/*");
    }
}

 替换SpringMVC主配置文件!

@Configuration
@ComponentScan(value = "具体扫描的名称",includeFilters =
        //只扫描标注注解为@Controller的类!
    @ComponentScan.Filter(type=FilterType.ANNOTATION,classes = {Controller.class})
    )
public class SpringMVCConfiguration implements WebMvcConfigurer{
    //静态资源放行格式一
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/img/**").addResourceLocations("/img/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
    }

    //静态资源放行格式二
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();;
    }
    /*
    * 两种静态放行方式取其一即可
    * */
}

至此基本上SpringMVC基本架构完成了!

三 SpringMVC的请求参数传递:

1 SpringMVC的请求参数传递:

这块就直接通过代码做示例既可,解释说明在代码中!

先了解这两个javabean:

public class Address {
    private String province;
    private String city;
    private String address;
}
public class User {
    private String name;
    private Integer age;

    private Address address;

    private List nick;

    private List
addresses; }

 controller层代码,参数的传递类型等全部在这一层:


@Controller
public class UserController {
    //方法传递普通类型参数,数量任意,类型必须匹配,参数可以是多个,但是匹配项必须包含参数名字有的!
    //http://localhost/requestParam1?name=nanfeng
    @RequestMapping("/requestParam")
    public String requestParam(String name){
        System.out.println(name);
        return "page.jsp";
    }
    //方法传递普通类型参数,数量任意,类型必须匹配,参数最后一个必须赋值,否则服务器报错
    //http://localhost/requestParam1?name=nanfeng&age=14
    @RequestMapping("/requestParam1")
    public String requestParam1(String name,int age){
        System.out.println(name+","+age);
        return "page.jsp";
    }

    //方法传递普通类型参数,使用@RequestParam参数匹配URL传参中的参数名称与方法形参名称
    //http://localhost/requestParam2?userName=Jock
    @RequestMapping("/requestParam2")
    //添加true属性后就必须带着匹配参数名来访问,否则访问无效
    public String requestParam2(@RequestParam(value = "userName",required = true) String name){
        System.out.println(name);
        return "page.jsp";
    }

    //方法传递POJO类型参数,URL地址中的参数作为POJO的属性直接传入对象
    //http://localhost/requestParam3?name=Jock&age=39
    @RequestMapping("/requestParam3")
    public String requestParam3(User user){
        System.out.println(user);
        return "page.jsp";
    }

    //当方法参数中具有POJO类型参数与普通类型参数嘶,URL地址传入的参数不仅给POJO对象属性赋值,也给方法的普通类型参数赋值
    //http://localhost/requestParam4?name=Jock&age=39
    @RequestMapping("/requestParam4")
    public String requestParam4(User user,int age){
        System.out.println("user="+user+",age="+age);
        return "page.jsp";
    }

    //使用对象属性名.属性名的对象层次结构可以为POJO中的POJO类型参数属性赋值
    //http://localhost/requestParam5?address.city=beijing
    @RequestMapping("/requestParam5")
    public String requestParam5(User user){
        System.out.println(user.getAddress().getCity());
        return "page.jsp";
    }

    //通过URL地址中同名参数,可以为POJO中的集合属性进行赋值,集合属性要求保存简单数据
    //http://localhost/requestParam6?nick=Jock1&nick=Jockme&nick=zahc
    @RequestMapping("/requestParam6")
    public String requestParam6(User user){
        System.out.println(user);
        return "page.jsp";
    }

    //POJO中List对象保存POJO的对象属性赋值,使用[数字]的格式指定为集合中第几个对象的属性赋值
    //http://localhost/requestParam7?addresses[0].city=beijing&addresses[1].province=hebei
    @RequestMapping("/requestParam7")
    public String requestParam7(User user){
        System.out.println(user.getAddresses());
        return "page.jsp";
    }
    //POJO中Map对象保存POJO的对象属性赋值,使用[key]的格式指定为Map中的对象属性赋值
    //http://localhost/requestParam8?addressMap['job'].city=beijing&addressMap['home'].province=henan
    @RequestMapping("/requestParam8")
    public String requestParam8(User user){
        System.out.println(user.getAddressMap());
        return "page.jsp";
    }

    //方法传递普通类型的数组参数,URL地址中使用同名变量为数组赋值
    //http://localhost/requestParam9?nick=Jockme&nick=zahc
    @RequestMapping("/requestParam9")
    public String requestParam9(String[] nick){
        System.out.println(nick[0]+","+nick[1]);
        return "page.jsp";
    }

    //方法传递保存普通类型的List集合时,无法直接为其赋值,需要使用@RequestParam参数对参数名称进行转换
    //http://localhost/requestParam10?nick=Jockme&nick=zahc
    @RequestMapping("/requestParam10")
    public String requestParam10(@RequestParam("nick") List nick){
        System.out.println(nick);
        return "page.jsp";
    }

}

 注解解释: 

@Controller注解: 就是一个控制层的bean标注。

@RequestParam参数绑定注解:

 public String requestParam2(@RequestParam(value = "userName",required = true ,defaultValue = "默认的值") String name){
        System.out.println(name);
        return "page.jsp";
    }

 @RequestMapping:请求处理器注解:可以做一些参基本数据的校验信息,类注解,方法注解!

@RequestMapping(
 value="/requestURL3", //设定请求路径,与path属性、value属性相同
 method = RequestMethod.GET, //设定请求方式
 params = "name", //设定请求参数条件
 headers = "content-type=text/*", //设定请求消息头条件
 consumes = "text/*", //用于指定可以接收的请求正文类型(MIME类型)
 produces = "text/*" //用于指定可以生成的响应正文类型(MIME类型)
 )
public String requestURL3() {
 return "/page.jsp";
}

 作为类注解:相当于访问资源路径添加了一层层级关系,其中的转发访问等资源需要同时添加这个层级目录,否则目标文件找不到,这块注意一下即可!

2 SpringMVC的参传递类型转换器

SpringMVC 对接收的数据进行自动类型转换,该工作通过 Converter 接口实现。SpringMVC的类型转换器很多,这块通过时间类型转换器进行分析!其他的转换参考即可!
(1)使用默认的类型转换器(无需任何的操作即可)
//http://localhost/requestParam11?date=2020/02/02
@RequestMapping("/requestParam11")
public String requestParam11(Date date){
 System.out.println("date="+date);
 return "page.jsp";
}

(2)使用自定义格式的类型转换器,SpringMVC的核心配置文件中添加





 
 
 
 
 
 
 
 
 
 
 

(3)@DateTimeFormat注解简化的格式,形参注解,成员变量注解

public String requestParam12(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date){
 System.out.println("date="+date);
 return "page.jsp";
}
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;

使用注解需要在mvc的配置文件中开启注解支持!

 (4)自定义类型转换器!

配置文件:







  
  
  
  
  
  
  
  

实现类:

//将字符串转化成date数据类型
public class MyDateConverter implements Converter {
 @Override
 public Date convert(String source) {
//根据转化的格式进行转化
 DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
 Date date = null;
 try {
 date = format.parse(source);
 } catch (ParseException e) {
 e.printStackTrace();
 }
 return date;
 }
}

四 SpringMVC响应数据:

示例(代码全部是复制的,但凡是个正常人一看就懂!):

@Controller
public class UserController {
    //测试服务器是否正常工作使用
    @RequestMapping("/showPage")
    public String showPage() {
        System.out.println("user mvc test.controller is running ...");
        return "page.jsp";
    }

    //forward:page.jsp转发访问,支持访问WEB-INF下的页面
    @RequestMapping("/showPage1")
    public String showPage1() {
        System.out.println("user mvc test.controller is running ...");
        return "forward:/WEB-INF/page/page.jsp";
    }

    //redirect:page.jsp重定向访问,不支持访问WEB-INF下的页面
    @RequestMapping("/showPage2")
    public String showPage2() {
        System.out.println("user mvc test.controller is running ...");
        return "redirect:/WEB-INF/page/page.jsp";
    }

    //页面简化配置格式,使用前缀+页面名称+后缀的形式进行,类似于字符串拼接
    @RequestMapping("/showPage3")
    public String showPage3() {
        System.out.println("user mvc test.controller is running ...");
        return "page";
    }

    //页面简化配置格式不支持书写forward
    @RequestMapping("/showPage4")
    public String showPage4() {
        System.out.println("user mvc test.controller is running ...");
        return "forward:page";
    }

    //最简页面配置方式,使用访问路径作为页面名称,省略返回值
    @RequestMapping("/showPage5")
    public void showPage5() {
        System.out.println("user mvc test.controller is running ...");
    }
}
@Controller
public class AccountController {
    //使用原生response对象响应数据
    @RequestMapping("/showData1")
    public void showData1(HttpServletResponse response) throws IOException {
        response.getWriter().write("message");
    }

    //使用@ResponseBody将返回的结果作为响应内容,而非响应的页面名称
    @RequestMapping("/showData2")
    @ResponseBody
    public String showData2(){
        return "{'name':'Jock'}";
    }

    //使用jackson进行json数据格式转化
    @RequestMapping("/showData3")
    @ResponseBody
    public String showData3() throws JsonProcessingException {
        Book book  = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);
        ObjectMapper om = new ObjectMapper();
        //这样返回前台的数据会出现乱码
        return om.writeValueAsString(book);
    }

    //使用SpringMVC注解驱动,对标注@ResponseBody注解的控制器方法进行结果转换,由于返回值为引用类型,自动调用jackson提供的类型转换器进行格式转换
    @RequestMapping("/showData4")
    @ResponseBody
    public Book showData4() {
        Book book  = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);
        return book;
    }

    //转换集合类型数据
    @RequestMapping("/showData5")
    @ResponseBody
    public List showData5() {
        Book book1  = new Book();
        book1.setName("SpringMVC入门案例");
        book1.setPrice(66.66d);

        Book book2  = new Book();
        book2.setName("SpringMVC入门案例");
        book2.setPrice(66.66d);

        ArrayList al = new ArrayList();
        al.add(book1);
        al.add(book2);
        return al;
    }
}
@Controller
public class BookController {
    //使用原生request对象传递参数
    @RequestMapping("/showPageAndData1")
    public String showPageAndData1(HttpServletRequest request) {
        request.setAttribute("name","itheima");
        return "page";
    }
    //使用Model形参传递参数
    @RequestMapping("/showPageAndData2")
    public String showPageAndData2(Model model) {
        //添加数据的方式,key对value
        model.addAttribute("name","Jock");
        Book book  = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);
        //添加数据的方式,key对value
        model.addAttribute("book",book);
        return "page";
    }

    //使用ModelAndView形参传递参数,该对象还封装了页面信息
    @RequestMapping("/showPageAndData3")
    public ModelAndView showPageAndData3(ModelAndView modelAndView) {
        //ModelAndView mav = new ModelAndView();    替换形参中的参数
        Book book  = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);

        //添加数据的方式,key对value
        modelAndView.addObject("book",book);
        //添加数据的方式,key对value
        modelAndView.addObject("name","Jockme");
        //设置页面的方式,该方法最后一次执行的结果生效
        modelAndView.setViewName("page");
        //返回值设定成ModelAndView对象
        return modelAndView;
    }

    //ModelAndView对象支持转发的手工设定,该设定不会启用前缀后缀的页面拼接格式
    @RequestMapping("/showPageAndData4")
    public ModelAndView showPageAndData4(ModelAndView modelAndView) {
        modelAndView.setViewName("forward:/WEB-INF/page/page.jsp");
        return modelAndView;
    }

    //ModelAndView对象支持重定向的手工设定,该设定不会启用前缀后缀的页面拼接格式
    @RequestMapping("/showPageAndData5")
    public ModelAndView showPageAndData6(ModelAndView modelAndView) {
        modelAndView.setViewName("redirect:page.jsp");
        return modelAndView;
    }
}

解释:

当处理器方法的返回值类型为String类型,即可通过具体的返回值设置访问的页面

@Controller
public class UserController {
 @RequestMapping("/showPage")
 public String showPage() {
 System.out.println("user mvc controller is running ...");
 return "page.jsp";
 }
}

注意:返回页面的路径拼串,只要核心配置文件做了添,单反返回的也买你数据就会自动添加后缀或者目录层级!


 
 

处理器名字同页面名字。可直接进行访问:

//当返回数据时候若是处理器名字和访问的返回也买你名字相同,则可绑定简写
//下面两个等同效果
@RequestMapping("/showPage5")
public void showPage5() {
}

@RequestMapping("/showPage5")
public String showPage5() {
 return "showPage5";
}

主要注解解释:

@ResponseBody 类注解,方法注解。标注返回值类型是字符串,其实就是json类型!

使用时maven坐标:其实下面两个依赖不用导入,在上马的依赖已经包含下面两个依赖,这是mavn的一依赖传递,在后面有时间时候在做maven的相关总结把!

 
    
      com.fasterxml.jackson.core
      jackson-core
      2.9.0
    

    
      com.fasterxml.jackson.core
      jackson-databind
      2.9.0
    

    
      com.fasterxml.jackson.core
      jackson-annotations
      2.9.0
    

五 SpringMVC获取原生得Servlet相关信息:

1 获取原生请求响应对象

将原生得请求响应作为处理器得参数即可:

示例:

@RequestMapping("/servletApi")
public String servletApi(HttpServletRequest request, 
 HttpServletResponse response, HttpSession session){
 //todo.....
}

2 获取请求头相关的信息

@RequestMapping("/headApi")
public String headApi(@RequestHeader("Accept-Language") String head){
 System.out.println(head);
 return "page.jsp";
}

核心注解:RequestHeader,参数为想获取的请求头的相关信息!请求头信息是键值对形式的!

3 获取Cookie相关的信息:

@RequestMapping("/cookieApi")
public String cookieApi(@CookieValue("JSESSIONID") String jsessionid){
 System.out.println(jsessionid);
 return "page.jsp";
}

核心注解@CookieValue 

4 获取Session相关的信息:

@RequestMapping("/sessionApi")
public String sessionApi(@SessionAttribute("name") String name){
 System.out.println(name);
 return "page.jsp";
}

核心注解: @SessionAttribute

在这放一套常用的SpringMVC坐标吧!(方便以后自己用到来粘贴)wu


    UTF-8
    1.8
    1.8
  

  
    
    
      javax.servlet
      javax.servlet-api
      3.1.0
      provided
    
    
    
      javax.servlet.jsp
      jsp-api
      2.1
      provided
    
    
    
      org.springframework
      spring-context
      5.1.9.RELEASE
    
    
      org.springframework
      spring-web
      5.1.9.RELEASE
    
    
    
      org.springframework
      spring-webmvc
      5.1.9.RELEASE
    

  

  
  
    
    
      
      
        org.apache.tomcat.maven
        tomcat7-maven-plugin
        2.1
        
          80
          /
        
      
    
  

五 SpringMVC异步请求响应

1 异步请求参数,异步请求发送是前端的人员的事情,我不是很了解:

直接上案例!利用ajax发送异步请求(请求参数是集合,集合中存储pojo数据在这补充):

@RequestMapping("/ajaxController")
    //使用@RequestBody注解,可以将请求体内容封装到指定参数中
    public String ajaxController(@RequestBody String message){
        System.out.println("ajax request is running..."+message);
        return "page.jsp";
    }

    @RequestMapping("/ajaxPojoToController")
    //如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中
    //注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射
    public String  ajaxPojoToController(@RequestBody User user){
        System.out.println("controller pojo :"+user);
        return "page.jsp";
    }

    @RequestMapping("/ajaxListToController")
    //如果处理参数是List集合且封装了POJO,且页面发送的数据是JSON格式的对象数组,数据将自动映射到集合参数中
    public String  ajaxListToController(@RequestBody List userList){
        System.out.println("controller list :"+userList);
        return "page.jsp";
    }

@Requestbody注解,参数注解,异步请求参数使用标注!

其实就是给参数添加上@Requestbody这个注解即可完成异步请求参数的接收!

2 异步响应:

直接上案例!

@RequestMapping("/ajaxReturnJson")
    @ResponseBody
    //基于jackon技术,使用@ResponseBody注解可以将返回的POJO对象转成json格式数据
    public User ajaxReturnJson(){
        System.out.println("controller return json pojo...");
        User user = new User();
        user.setName("Jockme");
        user.setAge(39);
        return user;
    }

    @RequestMapping("/ajaxReturnJsonList")
    @ResponseBody
    //基于jackon技术,使用@ResponseBody注解可以将返回的保存POJO对象的集合转成json数组格式数据
    public List ajaxReturnJsonList(){
        System.out.println("controller return json list...");
        User user1 = new User();
        user1.setName("Tom");
        user1.setAge(3);

        User user2 = new User();
        user2.setName("Jerry");
        user2.setAge(5);

        ArrayList al = new ArrayList();
        al.add(user1);
        al.add(user2);

        return al;
    }

@Responsebody注解 , 处理器注解(method),类注解!标注返回的数据为字符串类型,通常配合jsion为jsion串,告诉浏览器使用y字符串进行解析!通常就是html等!

3 跨域问题:

概念:跨域是指不同服务器之间的资源访问!

产生跨域的条件:请求协议不同,ip地址不同,端口号不同,只要是这三个任意一个不同就会产生跨域问题!

产生的问题:接收不到数据/接收数据异常,这种问题多出现在微服务上!
解决方式:在被访问的服务器的处理器(方法),加上注解@CrossOrigin 该注解可以写在方法上,也可以写在类上。
同源策略(概述) :同源策略(Same origin policy)是一种约定,它是浏览器最核心也 最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。 以说 Web 是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现 示例:

SpringMVC体系_第5张图片

@RequestMapping("/cross")
    @ResponseBody
    //使用@CrossOrigin开启跨域访问
    //标注在处理器方法上方表示该方法支持跨域访问
    //标注在处理器类上方表示该处理器类中的所有处理器方法均支持跨域访问
    @CrossOrigin
    public User cross(HttpServletRequest request){
        System.out.println("controller cross..."+request.getRequestURL());
        User user = new User();
        user.setName("Jockme");
        user.setAge(39);
        return user;
    }

@CrossOrigin注解标注处理器/类,就可以实现不同服务器之间数据访问!

小扩展,其实就是这个注解去改了请求头信息!

 六 SpringMVC拦截器:

拦截器: 是一种动态拦截方法调用的机制

作用:其实就是在方法前后做一些事情

实现原理:其实就是Spring的AOP

拦截器和过滤器的对比:

拦截器属于SpringMVC范围的,过滤器属于Servlet范围的:

看图:

SpringMVC体系_第6张图片

SpringMVC体系_第7张图片

 其实过滤器能干的事情拦截器都可以!

自定义拦截器(配置文件形式,注解的没用过,有点麻烦,后面找机会补上)

核心配置文件(用到参考修改即可):




    

    

    
    
        
        
            
            
            
            
            
            
            
            
            
            
            
            
            
        
        
        
            
            
        
        
            
            
        
    


拦截器类:

自定义拦截器类需要实现HandleInterceptor接口

//自定义拦截器需要实现HandleInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
    //处理器运行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        //handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装
        //返回值为false将拦截原始处理器的运行
        return true;
    }

    //处理器运行之后执行
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {
        //modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整

    }

    //所有拦截器的后置执行全部结束后,执行该操作
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        //ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理
        System.out.println("完成运行----c1");
    }
    //三个方法的运行顺序为    preHandle -> postHandle -> afterCompletion
}

 纯注解配置拦截器:

/**
 * WEB核心配置文件,可做多项操作,根据条件进行选择方法重写即可
 */
public class MyConfig implements WebMvcConfigurer {
    /***
     * 纯注解配置SpringMVC的拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //创建自定义的拦截器实现类
        HandlerInterceptor interceptor = new Handler();
        //拦截规则必须使用“/”开头,具体的拦截方式参考xml文件即可
        registry.addInterceptor(interceptor).addPathPatterns("/拦截规则");
        
        /**
         * 若是多个配置按照拦截器的拦截规则进行添加即可
         */

    }
}

拦截器的配置顺序:拦截器的配置顺序就是执行顺序,一般要求重要的先进行配置!

多个拦截器的配置执行顺序:

atfer执行是倒叙,其他两个方法不考虑返回false的情况下是根据handler对称执行

SpringMVC体系_第8张图片

拦截器是责任链模式的设计思想! 

七 文件上传下载:

其实就是根据MultipartResolver接口的实现类CojinmmonsMultipartResolver进行的,不累的话自己翻源码去看吧!其实还是用的阿帕奇的东西,Spring进行的整合!

maven坐标:

 
    
      commons-fileupload
      commons-fileupload
      1.4
    

核心配置(若是纯注解的直接将这个bean加载到容器即可,但是不管咋样名字都必须为multipartResolver):




    

    

    
    
    
        
    

代码(MultipartFile 参数名字必须传递过来的参数名字相同,SpringMVC接收参数的关系相同):

@Controller
public class FileUploadController {

    @RequestMapping("/fileupload")
    //参数中定义MultipartFile参数,用于接收页面提交的type=file类型的表单,要求表单名称与参数名相同
    public String fileupload(MultipartFile file,
                             MultipartFile file1,
                             MultipartFile file2,
                             HttpServletRequest request) throws IOException {
        long size = file.getSize();
        int length = file.getBytes().length;
        //获取文件类型,用于生成新的文件存储目录使用
        String contentType = file.getContentType();
        //获取上传文件绑定的形式参数名称,似乎没啥用
        String name = file.getName();
        //获取文件的真实名称
        String originalFilename = file.getOriginalFilename();
        //判断文件是否为空
        boolean empty = file.isEmpty();

        //首先判断是否是空文件,也就是存储空间占用为0的文件
        if (!file.isEmpty()) {
            //如果大小在范围要求内正常处理,否则抛出自定义异常告知用户(未实现)
            //获取原始上传的文件名,可以作为当前文件的真实名称保存到数据库中备用
            String fileName = file.getOriginalFilename();
            //设置保存的路径
            String realPath = request.getServletContext().getRealPath("/images");
            //保存文件的方法,指定保存的位置和文件名即可,通常文件名使用随机生成策略产生,避免文件名冲突问题
            file.transferTo(new File(realPath, file.getOriginalFilename()));
        }
        //测试一次性上传多个文件
        if (!file1.isEmpty()) {
            String fileName = file1.getOriginalFilename();
            //可以根据需要,对不同种类的文件做不同的存储路径的区分,修改对应的保存位置即可
            String realPath = request.getServletContext().getRealPath("/images");
            file1.transferTo(new File(realPath, file1.getOriginalFilename()));
        }
        if (!file2.isEmpty()) {
            String fileName = file2.getOriginalFilename();
            String realPath = request.getServletContext().getRealPath("/images");
            file2.transferTo(new File(realPath, file2.getOriginalFilename()));
        }
        return "page.jsp";
    }
}

 没啥好解释的,用到粘贴根据注释进行修改即可!

文件下载:访问资源文件所在的链接就行,不废话了!!!!!

 八 SpringMVC的异常处理机制:

方式一:

其实就是实现HanlerExceptionResover接口,在接口实现类中处理异常信息即可!实现类写完后将实现类配置成Spring能够识别的bean即可!老规矩,方式就这样,用到自己复制去修改即可!

示例:

//将实现HandlerExceptionResolver接口的类配置成Spring能够识别的bean即可完成异常信息的处理
@Component
public class ExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {
        //Object handler方法封装的对象,类似拦截器中的第一个方法!
        //ModelAndView对象是可以直接new出来的
        ModelAndView modelAndView = new ModelAndView();
        if( ex instanceof NullPointerException){
            modelAndView.addObject("msg","空指针异常");
        }else if ( ex instanceof  ArithmeticException){
            modelAndView.addObject("msg","算数运算异常");
        }else{
            modelAndView.addObject("msg","未知的异常");
        }
        modelAndView.setViewName("error.jsp");
        return modelAndView;
    }
}

方式二(前提是当前类是Spring能够识别的bean):

@ControllerAdvice注解:类注解,标注当前类是异常处理类!

@ExceptionHandler注解:方法注解,标注处理那种类型的异常,参数是异常类的字节码对象!

示例:


@Component
@ControllerAdvice
public class ProjectExceptionAdvice {

    @ExceptionHandler(BusinessException.class)
    public String doBusinessException(Exception ex, Model m){
        //使用参数Model将要保存的数据传递到页面上,功能等同于ModelAndView
        //业务异常出现的消息要发送给用户查看
        m.addAttribute("msg",ex.getMessage());
        return "error.jsp";
    }

    @ExceptionHandler(SystemException.class)
    public String doSystemException(Exception ex, Model m){
        //系统异常出现的消息不要发送给用户查看,发送统一的信息给用户看
        m.addAttribute("msg","服务器出现问题,请联系管理员!");
        //实际的问题现象应该传递给redis服务器,运维人员通过后台系统查看
        //实际的问题显现更应该传递给redis服务器,运维人员通过后台系统查看
        return "error.jsp";
    }

    @ExceptionHandler(Exception.class)
    public String doException(Exception ex, Model m){
        m.addAttribute("msg",ex.getMessage());
        //将ex对象保存起来
        return "error.jsp";
    }

}

异常处理这块的思路:在实际的开发中将业务的异常进行分类处理,业务异常,系统异常,....,将不同的问题反馈给不同的负责人员进行处理!

九 RestFul开发风格:

概述:RestFul开发风格其实就是一种开发约定习惯,并非是规则必须遵守,可以根据业务的习惯进行修改!说直白点就是将请求的数据信息隐藏到请求路径中!

优点:解决以往开发的明码问题!其实我我是不喜欢这种开发方式的,华丽花哨的,有没有本质上改变!

Restful开发时候一般的web.xml配置(配置不做解释,一看秒懂,就是开启对这些花里胡哨的访问格式的拦截,进行特定的过滤),老规矩,谁写都一样,直接粘贴使用即可




    
        characterEncodingFilter
        org.springframework.web.filter.CharacterEncodingFilter
        
            encoding
            UTF-8
        
    
    
        characterEncodingFilter
        /*
    

    
    
        HiddenHttpMethodFilter
        org.springframework.web.filter.HiddenHttpMethodFilter
    
    
        HiddenHttpMethodFilter
        DispatcherServlet
    

    
        DispatcherServlet
        org.springframework.web.servlet.DispatcherServlet
        
            contextConfigLocation
            classpath*:spring-mvc.xml
        
    
    
        DispatcherServlet
        /
    

controller层处理器的访问代码:



import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@ResponseBody
//设置rest风格的控制器
//@RestController
//设置公共访问路径,配合下方访问路径使用
@RequestMapping("/user/")
public class UserController {

    //rest风格访问路径完整书写方式
    @RequestMapping("/user/{id}")
    //使用@PathVariable注解获取路径上配置的具名变量,该配置可以使用多次
    public String restLocation(@PathVariable Integer id) {
        System.out.println("restful is running ....");
        return "success.jsp";
    }

    //rest风格访问路径简化书写方式,配合类注解@RequestMapping使用
    @RequestMapping("{id}")
    public String restLocation2(@PathVariable Integer id) {
        System.out.println("restful is running ....get:" + id);
        return "success.jsp";
    }

    //接收GET请求配置方式
    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    //接收GET请求简化配置方式
    @GetMapping("{id}")
    public String get(@PathVariable Integer id) {
        System.out.println("restful is running ....get:" + id);
        return "success.jsp";
    }

    //接收POST请求配置方式
    @RequestMapping(value = "{id}", method = RequestMethod.POST)
    //接收POST请求简化配置方式
    @PostMapping("{id}")
    public String post(@PathVariable Integer id) {
        System.out.println("restful is running ....post:" + id);
        return "success.jsp";
    }

    //接收PUT请求简化配置方式
    @RequestMapping(value = "{id}", method = RequestMethod.PUT)
    //接收PUT请求简化配置方式
    @PutMapping("{id}")
    public String put(@PathVariable Integer id) {
        System.out.println("restful is running ....put:" + id);
        return "success.jsp";
    }

    //接收DELETE请求简化配置方式
    @RequestMapping(value = "{id}", method = RequestMethod.DELETE)
    //接收DELETE请求简化配置方式
    @DeleteMapping("{id}")
    public String delete(@PathVariable Integer id) {
        System.out.println("restful is running ....delete:" + id);
        return "success.jsp";
    }

    //多参数配置
    @DeleteMapping("{id}/{name}")
    public String deleteTest(@PathVariable Integer id, @PathVariable String name) {
        System.out.println(id + "-----" + name);
        return "success.jsp";
    }
}

注解说明

注意下面两行其实是相同的作用,同时@PutMapping等都是相同的,依次类推:

@GetMapping("{id}")
@RequestMapping(value = "{id}", method = RequestMethod.GET)

@PathVariable参数注解,是Resuful风格专用绑定参数的注。多个参数绑定使用逗号隔开即可!

@RestController注解是@ResponeBody和@Controller注解的组合,关于这两个注解:           @ResponeBody是响应字符串不在资源中找页面,@Controller是表现层标注注解

关于Restful风格总言之就是将数据放在访问路径里面,做了表现层的封装而已!

十 SpringMVC的数据校验!

SpringMVC的数据数据校验还是使用到其他的技术。maven坐标,使用时候需要注意这种校验是针对javabean类型的进行数据校验,不能使用基本的数据类型(含String):

           
        
            javax.validation
            validation-api
            2.0.1.Final
        
        
        
            org.hibernate
            hibernate-validator
            6.1.0.Final
        

注意使用这套坐标的时候需要配置的tomcat的等级:

tomcat7 :搭配 hibernate-validator 版本 5
tomcat8.5 :搭配 hibernate-validator 版本 6

核心注解

@Validated这个注解是Spring包下的,参数注解,用于检验javabean中的属性相关的,支持分组校验,分组校验就是将需要校验的javabean中的属性分成组别进行校验,满足某些数据不是每次都需要进行校验的场景!

@Valid是org.hibernate下的,参数注解,除了不能满足分组,其他同上面的注解!

关于套校验对于非空的校验等级!(该坐标中含有很多类型校验的注解,用到再去百度,这块只做简单的示例)

SpringMVC体系_第9张图片

使用示例(GetSet方法省略):

public class Employee{
    //设定校验器,设置校验不通过对应的消息,设定所参与的校验组
    @NotBlank(message = "姓名不能为空",groups = {GroupA.class})
    private String name;//员工姓名

    //一个属性可以添加多个校验器
    @NotNull(message = "请输入您的年龄",groups = {GroupA.class})
    @Max(value = 60,message = "年龄最大值不允许超过60岁")
    @Min(value = 18,message = "年龄最小值不允许低于18岁")
    private Integer age;//员工年龄

    //实体类中的引用类型通过标注@Valid注解,设定开启当前引用类型字段中的属性参与校验
    @Valid
    private Address address;
}


//嵌套校验的实体中,对每个属性正常添加校验规则即可
public class Address {
    @NotBlank(message = "请输入省份名称")
    private String provinceName;//省份名称

    @NotBlank(message = "请输入城市名称")
    private String cityName;//城市名称

    @NotBlank(message = "请输入详细地址")
    private String detail;//详细住址

    @NotBlank(message = "请输入邮政编码")
    @Size(max = 6,min = 6,message = "邮政编码由6位组成")
    private String zipCode;//邮政编码
}

//校验范例,仅供参考
public class Employee2 implements Serializable {

    private String id;//员工ID

    private String code;//员工编号

    @NotBlank(message = "员工名称不能为空")
    private String name;//员工姓名

    @NotNull(message = "员工年龄不能为空")
    @Max(value = 60,message = "员工年龄不能超过60岁")
    @Min(value = 18,message = "员工年里不能小于18岁")
    private Integer age;//员工年龄

    @NotNull(message = "员工生日不能为空")
    @Past(message = "员工生日要求必须是在当前日期之前")
    private Date birthday;//员工生日

    @NotBlank(message = "请选择员工性别")
    private String gender;//员工性别

    @NotEmpty(message = "请输入员工邮箱")
    @Email(regexp = "@",message = "邮箱必须包含@符号")
    private String email;//员工邮箱

    @NotBlank(message = "请输入员工电话")
    @Pattern(regexp = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$",message = "手机号不正确")
    private String telephone;//员工电话

    @NotBlank(message = "请选择员工类别")
    private String type;//员工类型:正式工为1,临时工为2

    @Valid//表示需要嵌套验证
    private Address address;//员工住址
}

 分组:

//用于设定分组校验中的组名,当前接口仅提供字节码,用于识别
public interface GroupA {

控制层代码:

@Controller
public class EmployeeController {
    @RequestMapping(value = "/addemployee")
    public String addEmployee( @Validated({GroupA.class}) Employee employee, Errors errors, Model m) {
        if (errors.hasErrors()) {
            List fieldErrors = errors.getFieldErrors();
            System.out.println(fieldErrors.size());
            for (FieldError error : fieldErrors) {
                System.out.println(error.getField());
                System.out.println(error.getDefaultMessage());
                m.addAttribute(error.getField(), error.getDefaultMessage());
            }
            return "addemployee.jsp";
        }
        return "success.jsp";
    }


    @RequestMapping(value = "/addemployee2")
    //使用@Valid开启校验,使用@Validated也可以开启校验
    //Errors对象用于封装校验结果,如果不满足校验规则,对应的校验结果封装到该对象中,包含校验的属性名和校验不通过返回的消息
    public String addEmployee2(@Valid Employee employee, Errors errors, Model m) {
        //判定Errors对象中是否存在未通过校验的字段
        if (errors.hasErrors()) {
            //获取所有未通过校验规则的信息
            List fieldErrors = errors.getFieldErrors();
            System.out.println(fieldErrors.size());
            for (FieldError error : fieldErrors) {
                System.out.println(error.getField());
                System.out.println(error.getDefaultMessage());
                //将校验结果信息添加到Model对象中,用于页面显示,后期实际开发中无需这样设定,返回json数据即可
                m.addAttribute(error.getField(), error.getDefaultMessage());
            }
            //当出现未通过校验的字段时,跳转页面到原始页面,进行数据回显
            return "addemployee.jsp";
        }
        return "success.jsp";
    }

    /**
     * 注意。此类检测只能检测到javabean,是针对javabean中的属性进行的监测,若是使用基本类型(含字符串)会报错
     */
}

 校验规则和格式很多,用到那种再去参考吧,上面的案例用到在粘贴,案例全部来自收集,我做的只是将所有的案例进行整理!

 十一 SpringMVC开发时好习惯:

习惯。。就是和他人配合了,便于和人配合呗!

1 在前后交互传递数据时候可以进行统一的数据封装,便于前后台人员处理数据!其实就是将结果数据进行统一的格式传递!

例如:后台响应数据进行rest的:不好说,直接上案例,一看秒懂:mv

@Controller
@ResponseBody
public class ReturnResultRule {
    public Result getUser(){
        //调用业务层获取数据,然后将数据封装到Result中进行返回数据
        //关于result类前后台进行约定
        return new Result("message","sdsd",true);
    }
}


public class Result {
    /**
     * 操作结果携带的信息提示
     */
    private String message;
    /**
     * 数据封装
     */
    private Object object;
    /**
     * 操作成功否
     */z
    private  boolean flag;
//全参构造,空参构造,get,set,toString都得提供,防止出错
}

SpringMVC的基本信息到这完结! 

     

你可能感兴趣的:(Spring,mvc)