SpringMVC详解

一、SpringMVC

1.1 什么是SpringMVC

Java开源框架,Spring Framework的一个独立模块

MVC框架,在项目中开辟MVC层次架构

对控制器中的功能包装简化扩展践行工厂模式,功能架构在工厂之上。

1.2 MVC架构

1.2.1 概念

名称 职责
Model 模型:承载数据,并对用户提交请求进行计算的模块。分为两类,一类称为数据承载Bean,一类称为业务处理Bean。所谓数据承载Bean是值实体类,专门承载业务数据的,如Student、User等。而业务处理Bean则是指Service或Dao对象,专门用于处理用户提交请求的
View 视图:渲染数据,生成页面。对应项目中的Jsp , html 等 作用是与用户交互 展示数据
Controller 控制器:用于将用户请求转发给相应的Model进行处理,并处理Model的计算结果向用户提供相应响应

1.2.2 MVC工作流程:

  1. 用户通过View页面向服务端发送请求,可以是表单请求、超链接请求、AJAX请求等。

  2. 服务端Controller控制器接收到请求后对请求进行解析,找到相应的Model对用户请求进行处理。

  3. Model处理后,将处理结果再交给Controller。

  4. Controller接到处理结果后,根据处理结果找到要作为向客户端发回的响应View页面。页面经渲染后,再发给客户端。

1.2.3 优点

  • MVC是现下软件开发中的最流行的代码结构形态;

  • 人们根据负责的不同逻辑,将项目中的代码分成 M V C 3个层次;

  • 层次内部职责单一,层次之间耦合度低;

  • 符合低耦合 高内聚的设计理念。也实际有利于项目的长期维护。

二、开发流程

2.1 导入依赖

<!--——————————加入springMVC依赖—————————-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>

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

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

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

此控制器在接收到请求后,还会负责springMVC的核心的调度管理,所以既是前端又是核心。

  • 补充:DispatcherServlet前端控制器,是框架提供的,作用统一处理请求和响应,整个流程的控制中心,是由它来调用其他组件处理用户的请求。

web.xml文件配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--前端控制器-->
    <servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 局部参数:声明配置文件位置 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!-- Servlet启动时刻:可选 -->
        <!--DispatcherServlet前端控制器是springmvc中非常重要的一个组件,内置了很多初始化的工作,所以让他随着服务器的启动而启动
            提前把初始化工作做好,避免第一次访问的时候速度很慢
        -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc</servlet-name>
        <!--
            这里设置的是前端控制器可以处理的请求路径/表示拦截处理jsp以外的所有请求
            也就是说处理以.jsp结尾的请求其他请求都要经过前端控制器,这里注意不要写成/*,/*表示匹配所有路径
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 此过滤器会进行:request.setCharactorEncoding("utf-8"); -->
    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

2.3 后端控制器

等价于之前定义的Servlet。

@Controller // 交由spring创建bean对象
@RequestMapping("/hello") // 访问路径
public class HelloController {

    @RequestMapping("/hello1")
    public String hello(){
        return "index"; // 跳转到index.jsp
    }

    @RequestMapping("/hello2")
    public String hello2(){
        return "pages/main"; // 跳转到pages包下的main.jsp
    }
}

2.4 springmvc.xml文件配置

<beans 	xmlns="http://www.springframework.org/schema/beans"
          xmlns:context="http://www.springframework.org/schema/context"
          xmlns:mvc="http://www.springframework.org/schema/mvc"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
							http://www.springframework.org/schema/beans/spring-beans.xsd
							http://www.springframework.org/schema/context
							http://www.springframework.org/schema/context/spring-context.xsd
							http://www.springframework.org/schema/mvc
							http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--—— 告知springmvc哪些包中存在被注解的类 ——-->
    <context:component-scan base-package="com.ymk.controller"/>
    <!--—— 注册注解开发驱动 ——-->
    <mvc:annotation-driven/>
    <!-- 视图解析器
         作用:1.捕获后端控制器的返回值="index"
              2.解析: 在返回值的前后 拼接 ==> "/index.jsp"
     -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--—— 前缀 ——-->
        <property name="prefix" value="/"/>
        <!--—— 后缀 ——-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

2.5 浏览器访问

       URL地址栏输入:

  • http://localhost:8080/hello/hello1
  • http://localhost:8080/hello/hello2

三、接受请求参数

3.1基本类型参数

       请求参数和方法的形参同名即可。

  • springMVC默认可以识别的日期字符串格式为: YYYY/MM/dd HH:mm:ss
  • 通过@DateTimeFormat可以修改默认日志格式
    @RequestMapping("/test1")
    public String test1Param(Integer id, String name, Boolean gender,@DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday){
        // springmvc自动接收参数,并且转换参数类型
        System.out.println(id);
        System.out.println(name);
        System.out.println(gender);
        System.out.println(birthday);
        return "index";
    }

浏览器访问: http://localhost:8080/.../test1?id=001&name=张三&gender=true&birthday=2002-12-11

3.2实体收参

请求参数和实体类的属性需要同名。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String name;
    private Boolean gender;
    /**
     * 设置日期格式
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;
}
    @RequestMapping("/test2")
    public String test2Param(User user){
        System.out.println(user);
        return "index";
    }

浏览器访问:http://localhost:8080/.../test2?id=001&name=张三&gender=true&birthday=2000-11-22

3.3 数组收参

简单类型数组

<form action="http://localhost:8080/param/test3">
    <input type="checkbox" name="hobby" value="fb">足球
    <input type="checkbox" name="hobby" value="bb">篮球
    <input type="checkbox" name="hobby" value="vb">排球
    <input type="submit" value="提交">
</form>
    @RequestMapping("/test3")
    public String test3Param(String[] hobby){
        for (String s : hobby) {
            System.out.println(s);
        }
        return "index";
    }

浏览器访问:http://localhost:8080/.../test3?hobby=football&hobby=basketball 

3.4 集合收参

@Data
public class UserList {
	private List<User> users;
}
@RequestMapping("/test4")
public String testParam4(UserList userList){
    for(User user:userList.getUsers()){
        System.out.println(user);
    }
    return "index";
}

浏览器访问:

post请求:http://.../test4?userList[0].id=111&users[0].name=tom&users[0].gender=false&users[0].birthday=2000-04-02&users[1].id=2&.... 

3.5 路径参数

@RequestMapping("/hello/{id}")
// @PathVariable将{id}路径匹配到值赋给id参数
// 路径名和参数名相同则@PathVariable("id")可简写为 @PathVariable
public String testParam5(@PathVariable("id") Integer id){
    System.out.println("id:"+id);            
    return "index";
}
// http://localhost:8989/.../hello/10   {id}匹配到10

注意:@PathVariable将{id}路径匹配到值赋给id参数

路径名和参数名相同则@PathVariable("id")可简写为 @PathVariable

@RequestMapping("/hello/{username}")
public String testParam6(@PathVariable("username") String name){//将{username}路径匹配到的值赋给name参数
    System.out.println("username:"+name);
    return "index";
}
// http://localhost:8989/.../hello/tom   {username}匹配到tom

3.6中文乱码

       1.页面中字符集统一

  • JSP : <%@page  pageEncoding="utf-8" %>
  • HTML : <meta charset="UTF-8">

2.tomcat中字符集设置,对get请求中,中文参数乱码有效

 3.在web.xml中设置此filter,对post请求中,中文参数乱码有效

<!-- 此过滤器会进行:request.setCharactorEncoding("utf-8"); -->
<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

四、跳转

4.1转发

@Controller
@RequestMapping("/forw")
public class ForwardController {
    
    @RequestMapping("/test1")
    public String test1(HttpServletRequest request){
        System.out.println("test forward1");
        // 这也是转发,是走视图解析器的转发
        // return "index";

        //请求转发传值通过request.setAttribute
        request.setAttribute("name","zs");
        // 这种是不走视图解析器的转发
        return "forward:/page/success.jsp";
    }

    @RequestMapping("/test2")
    public String testForward2(){
        System.out.println("test forward2");

        // 转发到 /forw/test1
        return "forward:test1"; // 这种是相对路径(转发到本类中的test1)

        // 转发到 /forw/test1
        // return "forward:/forw/test1"; // 这种是绝对路径
    }
}
  • test1中model.addAttribute("name",name),在jsp中取值方式:${name}
  • 注意:转发也可以不走视图解析器,如:forward:/page/success.jsp

4.2重定向

@Controller
@RequestMapping("/redir")
public class RedirectController {

    @RequestMapping("/test1")
    public String test1(HttpSession session){
        System.out.println("test redirect1");

        // 重定向传值通过session.setAttribute
        session.setAttribute("name","ls");
        // 这种是不走视图解析器的转发
        return "redirect:/page/success.jsp";
    }

    @RequestMapping("/test2")
    public String testForward2(){
        System.out.println("test redirect2");
        
        // 重定向到 /redir/test1
        return "redirect:test1"; // 这种是相对路径(转发到本类中的test1)
        
        // 重定向到 /redir/test1
        // return "redirect:/redir/test1"; // 这种是绝对路径
    }
}

4.3 跳转细节

  1. 在增删改之后,为了防止请求重复提交,重定向跳转
  2. 在查询之后,可以做转发跳转

五、传值

C得到数据后,跳转到V,并向V传递数据。进而V中可以渲染数据,让用户看到含有数据的页面。

  • 转发跳转:    Request作用域
  • 重定向跳转:Session作用域

5.1 Request和Session

转发传给页面值

    @RequestMapping("/test1")
    public String testServlet(HttpServletRequest request, User user){
        user.setName("张三");
        request.setAttribute("user",user);
        System.out.println("scope test1");
        return "forward:/page/success.jsp";
        //jsp中取值方式${user.name}
    }

重定向传给页面值

    @RequestMapping("test2")
    public String testServlet2(HttpSession session,User user){
        user.setName("李四");
        session.setAttribute("user",user);
        System.out.println("scope test1");
        return "forward:/page/success.jsp";
        //jsp中取值方式${user.name}
    }

5.2 JSP中取值

//jsp中用EL表达式 取值即可
<fmt:formatDate value="${user.birth}" pattern="yyyy-MM-dd"/> <br/>
${user.birth} <br>
${age}

5.3Model

    //model中的数据等价于放在了request中,会在V渲染之前,将数据复制一份给request
    @RequestMapping("/test3")
    public String testData(Model model){
        // model中的数据等价于放在了request汇总
        model.addAttribute("name", "王二1");

        //转发带.jsp不走视图解析器
        return "forward:/page/success.jsp";
        //jsp中取值方式${name}
    }

5.4 ModelAndView

 //modelandview 封装了model和view
    @RequestMapping("/test4")
    public ModelAndView testData(){//返回值类型为ModelAndView
        //新建ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();

        // 使用model存储数据
        modelAndView.addObject("age",18);

        // 设置视图名,即如何跳转
        modelAndView.setViewName("page/success"); //等价 return "page/success";
        return modelAndView;
        //jsp中取值方式${age}
    }

5.5 @SessionAttributes[不用]

  • @SessionAttributes({"gender","name"}) :model中的 name和gender 会存入session中

  • SessionStatus 移除session

@Controller
@SessionAttributes({"gender","name"}) // model中的 name和gender 会存入session中
public class UserController {
    @RequestMapping("/hello")
    public String hello(Model m){
        m.addAttribute("gender",true); // 会存入session
        mv.addObject("name","zhj"); // 会存入session
        return "index";
    }
    @RequestMapping("/hello2")
    public String hello(SessionStatus status){
        // 移除通过SessionAttributes存入的session
        status.setComplete();
        return "index";
    }
}

5.6 补充

使用Map和ModelMap也可以在页面中也可以通过${user}取值。

    @RequestMapping("/test5")
    public String test5(Map<String,Object> map){
        User user = new User();
        user.setName("阿伟");
        user.setBirthday(new Date());
        map.put("user", user);
        return "page/success";
    }
    @RequestMapping("/test6")
    public String test6(ModelMap map){
        User user = new User();
        user.setName("阿伟");
        user.setBirthday(new Date());
        map.put("user", user);
        return "page/success";
    }

六、静态资源

6.1静态资源问题

静态资源:html,js文件,css文件,图片文件

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

在SpringMVC中DispatcherServlet也采用了 “/” 作为url-pattern, 则项目中不会再使用全局的Serlvet,则静态资源不能完成访问。

6.1.2 解决方案1

如果DispathcerServlet采用其他的url-pattern,web.xml中所有访问handler的路径都要以action结尾!!

<servlet>
  	<servlet-name>mvc9</servlet-name>
  	<servlet
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值