Spring——SpringMVC整合

一:SpringMVC

java开源框架,Spring Framework的一个独立模块。
MVC框架,在项目中开辟MVC层次架构
对控制器中的功能 包装 简化 扩展践行工厂模式,功能架构在工厂之上

MVC : Model View Controller

模型 视图 控制器
模型:即业务模型,负责完成业务中的数据通信处理,对应项目中的 service和dao
视图:渲染数据,生成页面。对应项目中的Jsp
控制器:直接对接请求,控制MVC流程,调度模型,选择视图。对应项目中的Servlet

MVC是现下软件开发中的最流行的代码结构形态;
人们根据负责的不同逻辑,将项目中的代码分成 M V C 3个层次;
层次内部职责单一,层次之间耦合度低;
符合低耦合 高内聚的设计理念。也实际有利于项目的长期维护。

二. 开发流程

2.1 废话不多说先导依赖


    org.springframework
    spring-webmvc
    4.3.6.RELEASE

2.2 配置核心(前端)控制器

作为一个MVC框架,首先要解决的是:如何能够收到请求!

所以MVC框架大都会设计一款前端控制器,选型在 Servlet 或 Filter两者之一,在框架最前沿率先工作,接收所有请求。

此控制器在接收到请求后,还会负责springMVC的核心的调度管理,所以既是前端又是核心。
**为了解决这个问题,我们需要在web.xml中添加一个servlet用来接受所有请求并交给Spring工厂进行操作**


    mvc9
    org.springframework.web.servlet.DispatcherServlet
 
    
        contextConfigLocation
        classpath:mvc.xml
    
    
    1
   


    mvc9
    /

名字可以随意 不影响,这样,所有的请求我们就都可以接收到了

2.3 后端控制器

请求我们接受了,接下来我们就要进行处理请求,以前我们通过servlet进行处理,现在我们要写的等价于之前的servlet

下面是一个例子:

@Controller //声明这是一个控制器
@RequestMapping("/hello")  //访问路径 ,等价于url-pattern
public class HelloController {
    @RequestMapping("/test1")  //访问路径
    public String hello1(){
        System.out.println("hello world");
        return "index"; // 跳转:/index.jsp  
    }
    @RequestMapping("/test2") //访问路径
    public String hello2(){
        System.out.println("hello c9");
        return "views/users";//  跳转:/views/user.jsp
    }
}

2.4 配置文件

默认名称:核心控制器名-servet.xml 默认位置:WEB-INF
随意名称:mvc.xml 随意位置:resources 但需要配置在核心控制器中



    
    
    
    
    
    
        
        
        
        
    

3. 接收请求参数

通过控制器中方法的形参 接收请求参数
请求参数 要和 方法的形参同名

// id  name gender
// springMVC默认可以识别的日期字符串格式为: YYYY/MM/dd HH:mm:ss
// http://localhost:8989/xxx/../text1?id=1&name=zzz&gender=false&birth=2018-12-12 12:20:30
@RequestMapping("/test1")
public String testParam1(Integer id,
                         String name,
                         Boolean gender,
                         @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")Date birth){
    System.out.println("test param1");
    return "index";
}

3.2 实体收参(建议)

请求参数和实体的属性 同名即可(会自动帮助我们封装成对象,超省事的)

public class User {
    private Integer id;
    private String name;
    @DateTimeFormat(pattern="yyyy-MM-dd")
    private Date birth;
    private Boolean gender;
    //set/get ...
}

//http://localhost:8989/.../test2?id=1&name=zzz&gender=false&birth=2018-12-12 12:20:30
@RequestMapping("/test2")
public String testParam2(User user){
    System.out.println("test param2");
    System.out.println("user:"+user);
    return "index";
}

3.5 中文乱码

首先,页面中字符集统一
JSP : <%@page pageEncoding="utf-8" %>
HTML :
其次,tomcat中字符集设置,对get请求中,中文参数乱码有效
Tomcat配置:URIEncoding=utf-8
最后,设置此filter,对post请求中,中文参数乱码有效


    encoding
    org.springframework.web.filter.CharacterEncodingFilter
    
        encoding
        utf-8
    


    encoding
    /*

4. 跳转

跳转关键字 forward: redirect:

4.1 C-->V controller--->view
【C-->V】
@RequestMapping("/test1")
public String testJump1(){
    System.out.println("test jump1");
    //重定向跳转   /index.jsp
    //return "redirect:/index.jsp";
    //转发跳转  /views/users.jsp
    return "forward:/views/users.jsp";
}

4.2 C-->C

【C-->C】
@RequestMapping("/test2")
public String testJump2(){
    System.out.println("test jump2");
    //转发跳转到  /jump/test1
    //return "forward:/jump/test1";
    //跳转到当前类下的 路径为test1的方法中
    //return "forward:test1";
    //重定向到 /jump/test1
    return "redirect:test1";
}

4.3 跳转细节

1.在增删改之后,为了防止请求重复提交,重定向跳转
2.在查询之后,可以做转发跳转
3.C到C,一般是增删改后衔接一个查询
4.C到V,一般是查询后衔接一个视图

4.4 jsp需要注意的细节

1.不应该直接访问jsp,应该先过C,查到数据后,在转发jsp(jsp需要数据的支撑)
2.可以将所有jsp都放入 WEB-INF目录下,即可强制不接受外界直接访问,只能由C转发(只能转发,哪怕是重定向也无法访问该目录下的jsp文件)

五 传值问题

在后端传值一般都存在request作用域中,如果需要长期保持用户登录信息等,可以存放在session中

六 SpringMVC中的Model ,ModelAndView 对象

Model对象的作用基本和request的作用一致
而ModelAndView对象即封装了数据,也封装也view

七 SpringMVC中的静态资源

静态资源指的是:html,js文件,css文件,图片等

静态文件没有url-pattern,所以默认是访问不到的,之所以可以访问,是因为,tomcat中有一个全局的servlet:org.apache.catalina.servlets.DefaultServlet,它的url-pattern是 "/",是全局默认的Servlet. (最后都不处理就轮到他了) 所以每个项目中不能匹配的静态资源的请求,有这个Servlet来处理即可。

但是在SpringMVC中的核心构件DispatcherServlet也采用了“/”来作为url-pattern,所以项目中的全局默认servlet就无法在进行使用,静态资源访问也就无法完成

7.1 解决方案1

DispathcerServlet采用其他的url-pattern
此时,所有访问handler的路径都要以 action结尾!!(action只是习惯,在这里可以随意填)

*.action

7.2 解决方案2

DispathcerServlet的url-pattern依然采用 "/",但追加配置



8. JSON处理(重重重重重重重重重重点)

JSON是前后端进行数据交互的一种重要手段,而在SpringMVC中采用的默认JSON解决方案是JackSon,只需要导入Jackson的依赖,就可以使用

8.1 导入依赖



    com.fasterxml.jackson.core
    jackson-databind
    2.9.8



    com.alibaba
    fastjson
    1.2.54

8.2 使用@ResponseBody(将handler的返回值,转换成json并将json响应给客户端。)

简单举例一下:

@RequestMapping("/test1")
@ResponseBody //将handler的返回值,转换成json(jackson),并将json响应给客户端。
public User hello1(){
    System.out.println("hello world");
    User user = new User();
    return user;
}
//@ResponseBody还可以用在handler的返回值上
@RequestMapping("/test2")
public @ResponseBody List hello2(){
    System.out.println("hello world");
    List users = Arrays.asList(new User(),new User());
    return users;
}

8.3 jackson的日期格式化

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
作用:将前端传过来的json串中的日期转换为指定的格式

public class User implements Serializable{
    private Integer id;
    private String name;
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date birth;
    ....

8.4 FastJson(又到最喜欢的FastJson环节啦~~~)

因为SpringMVC中默认使用的是jackson所以如果我们想要使用FastJson还需要在工厂中安装FastJson

8.4.1 FastJson的安装(废话不多说,上代码)

    
        
            
            
                
                    application/json
                
            
        
    

至于使用方式,和jackson基本没差别

8.4.3 日期格式化

@JSONField(format="yyyy/MM/dd")

public class User implements Serializable{
    private Integer id;
    private String name;
    @JSONField(format="yyyy/MM/dd")
    private Date birth;
    ...

8.5 @RestController

等价于在本类的所有Handler中都添加了@ResponseBody

@RestController // 等价于在本类的所有Handler中都添加了@ResponseBody
@RequestMapping("/json")
public class MyController {

    @RequestMapping("/test1")
    public User queryOneUser(Integer id){
        ....
    }
}

8.6 使用@RequestBody

@RequestBody, 接收Json参数 并将其自动转换为java对象

@RequestMapping("/users")
public String addUser(@RequestBody User user){//@RequestBody将请求体中的json数据转换为java对象
    System.out.println("cap2");
    System.out.println("Post user :"+user);
    return "index";
}

9. 异常解析器

项目中会面临各种异常。
1. 运行时异常,大多会在开发测试阶段解决掉。
2. 非运行时异常,是必须要处理的。
3. 业务异常,是根据业务要求,在出现非法情况时,人为抛出的。

9.1 异常处理方案

DAO,Service的所有异常,必须无条件上抛,全部集中到C
C中处理所有异常,将不同的异常转发到不同的错误处理结果中

C中的每个Handler不再自己处理异常,而是直接上抛所有异常。
定义一个“异常解析器” 集中捕获处理 所有异常

public class MyExResolver implements HandlerExceptionResolver{
    /**
     * 异常解析器:主体逻辑
     * 执行时刻:当handler中抛出异常时,会执行:捕获异常,并可以跳到错误页面
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex) {
        ex.printStackTrace();//打印异常栈
        //创建一个ModelAndView
        ModelAndView mv = new ModelAndView();
        //识别异常
        if (ex instanceof Exception1) {
            mv.setViewName("redirect:/dispatch/login/page");
        }else if(ex instanceof Exception2){
            mv.setViewName("redirect:/dispatch/error1/page");
        }else{
            mv.setViewName("redirect:/dispatch/error");
        }
        return mv;
    }
}
    

10. 拦截器(类似于过滤器?????)

作用:抽取c中的冗余功能

public class MyInter1 implements HandlerInterceptor{
    //主要逻辑:在handler之前执行:抽取handler中的冗余代码
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        System.out.println("pre~~~");
        if(1==2){
            response.sendRedirect("/springMVC_day2/index.jsp");//响应
            return false;//中断请求
        }
        return true;//放行,后续的拦截器或handler就会执行
    }
    //在handler之后执行:进一步的响应定制
    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("post~~");
    }
    //在页面渲染完毕之后,执行:资源回收
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("after~~");
    }
}
10.2 配置拦截路径

    
        
        
          /inter/testaa  /inter/test22  /inter/testssssss
         /inter/a/b/c/d   /inter/cc/ss/dfd
         不拦截此路径
         拦截器类
    

多个拦截器,拦截相同的位置: A-->B -->Handler --> B--> A

11. spring整合

11.1 整合思路

此时项目中有两个工厂

  • DispatcherServlet 启动的springMVC工厂==负责生产C及springMVC自己的系统
    组件
  • ContextLoaderListener 启动的spring工厂==负责生产其他所有组件
  • springMVC的工厂会被设置为spring工厂的子工厂,可以随意获取spring工厂中
    的组件
  • 整合过程,就是累加:代码+依赖+配置。然后将service注入给controller即可
11.2 整合技巧

两个工厂不能有彼此侵入,即,生产的组件不能有重合。



    



    

总结:学代码就是一个不断学新的,不断整合,不断推翻的过程,环环相扣,要不想
被狠狠拍在沙滩上,还是要好好学习啊!

你可能感兴趣的:(Spring——SpringMVC整合)