SpringMVC

SpringMVC

Spring MVC是Spring框架的一部分,主要用于构建Web应用程序。它遵循了模型-视图-控制器(MVC)的设计模式。在Spring MVC中,模型代表数据和业务逻辑,视图是用于呈现数据的界面,而控制器处理用户的请求并调用后端服务。

使用Spring MVC的步骤大致如下:

  1. 设置DispatcherServlet:这是Spring MVC的核心,用于拦截请求并分发给相应的处理器。
  2. 创建控制器:控制器接受用户输入,并调用模型以处理数据。
  3. 定义请求映射:控制器中的方法可以通过注解来映射具体的请求路径。
  4. 创建视图:可以是JSP、HTML或其他模板,用于展示数据。
  5. 配置Spring的配置文件或使用注解来指定组件、视图解析器等。

1. 快速入门

1)导入依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.8</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.8</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.8</version>
</dependency>

2)在web.xml中配置servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         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>springDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <!-- springmvc 的配置文件和以前 spring 的配置文件类似 -->
            <param-value>classpath:applicationContext-mvc.xml</param-value>
        </init-param>
        <!-- 在 web 项目启动时,就加载这个 servlet 实例 1 表示加载的顺序号-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>springDispatcherServlet</servlet-name>
        <!-- 为了支持 rest 风格的 url 这里的 url-patther 需要写成 / -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

3)创建applicationContext-mvc.xml,配置视图解析器

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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">
    <!-- 配置自动扫描包 -->
    <context:component-scan base-package="com.lhs.controller"/>
    <!-- 配置 SpringMVC 的视图解析器, 比如我们的 controller return 的是 ok
        那么这个页面就是 /WEB-INF/pages/ok.jsp
        -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

4)创建登录界面web/login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>登录</title>
    </head>
    <body>
        <h3>登录页面</h3>
        <form action="login">
            u:<input name="username" type="text"> <br/>
            p:<input name="password" type="password"><br/>
            <input type="submit" value="登录">
        </form>
    </body>
</html>

5)在创建返回界面web-info/pages/login_ok.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>登录成功</title>
    </head>
    <body>
        <h1>恭喜 登录成功!</h1>
    </body>
</html>

6)创建userService,当接收到表单提交的数据后返回login_ok.jsp

@Controller
public class UserServlet {
    @RequestMapping("/login")
    public String login(){
        System.out.println("login...");
        return "login_ok";
    }
}

7)配置并启动tomcat访问登录界面完成测试

2. 执行流程

请添加图片描述

3. @RequestMapping

@RequestMapping 注解可以修饰方法,还可以修饰类 当同时修饰类和方法时,请求的 url 就是: /类请求值/方法请求值

@RequestMapping 还可以指定请求的方式(post/get/put/delete…),默认的请求方式为Get和Post

使用@GetMapping@PostMapping@PutMapping@DeleteMapping可替代@RequestMapping,相当于指定了请求方式

@Controller
@RequestMapping("/user")
public class UserServlet {
    @RequestMapping(value = "/login",method = RequestMethod.GET)
    public String login(){
        System.out.println("login...");
        return "login_ok";
    }
}

@RequestMapping 支持 Ant 风格资源地址:

  • ?:匹配文件名中的一个字符
  • *:匹配文件名中的任意字符
  • **: 匹配多层路径

示例:

  • /user/*/createUser : 匹配 /user/aaa/createUser、/user/bbb/createUser 等 URL
  • /user/**/createUser : 匹配 /user/createUser、/user/aaa/bbb/createUser 等 URL
  • /user/createUser?? : 匹配 /user/createUseraa、/user/createUserbb 等 URL

4. 映射请求数据

4.1 获取参数值

我们可以通过@RequestParam注解来接收请求参数值

@Controller
public class UserServlet {
    @RequestMapping(value = "/login")
    public String login(@RequestParam(value = "username",required = false) String name){
        System.out.println(name);
        return "login_ok";
    }
}

说明:

  • @RequestParam : 表示说明一个接受到的参数
  • value=“username” : 接收的参数名是 username
  • required=false : 表示该参数可以有,也可以没有,如果 required=true,表示必须传递该参数

4.2 获取请求头

我们可以通过@RequestHeader注解来接收请求头

@Controller
public class UserServlet {
    @RequestMapping(value = "/login")
    public String login(@RequestParam(value = "username",required = true) String name,
                        @RequestHeader("Host") String host){
        System.out.println(name);
        System.out.println(host);
        return "login_ok";
    }
}

4.3 获取javabean形式的数据

我们可以使用一个javabean来接收请求参数

示例:

1)创建Pet.java

public class Pet {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Pet{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

2)创建Master.java

public class Master {
    private Integer id;
    private String name;
    private Pet pet;
    public Pet getPet() {
    return pet;
    }
    public void setPet(Pet pet) {
    this.pet = pet;
    }
    public Master() {
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Master{" +"id=" + id +
                ", name='" + name + '\'' +
                ", pet=" + pet +
                '}';
    }
}

3)创建表单界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>添加主人和宠物</title>
</head>
<body>
<h3>添加主人和宠物</h3>
<form action="login" method="post">
    主人号:<input type="text" name="id"><br>
    主人名:<input type="text" name="name"><br>
    宠物号:<input type="text" name="pet.id"><br>
    宠物名:<input type="text" name="pet.name"><br>
    <input type="submit" value="添加主人和宠物">
</form>
</body>
</html>

4)创建Servlet接收请求数据

@Controller
public class UserServlet {
    @RequestMapping(value = "/login")
    public String login(Master master){
        System.out.println(master);
        return "login_ok";
    }
}

5)测试

输出:Master{id=1, name=‘lhs’, pet=Pet{id=2, name=‘xh’}}

4.4 获取servlet api

我们在MVC框架中也能获取到原生的Servlet Api

1)导入依赖

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>servlet-api</artifactId>
    <version>6.0.53</version>
</dependency>

2)获取HttpServletRequestHttpServletResponse

@Controller
public class UserServlet {
    @RequestMapping(value = "/login")
    public String login(HttpServletRequest request, HttpServletResponse response){
        System.out.println(request.getParameter("username"));
        System.out.println(request.getParameter("password"));
        return "login_ok";
    }
}

还可以通过这种方式获取到HttpSession

@Controller
public class UserServlet {
    @RequestMapping(value = "/login")
    public String login(HttpServletRequest request, HttpServletResponse response, HttpSession session){
        System.out.println(request.getParameter("username"));
        System.out.println(request.getParameter("password"));
        System.out.println(session);
        return "login_ok";
    }
}

5. 模型数据

5.1 将数据放入request域

在控制器中通过javabean接收到的数据会传递到视图层,我们也可以手动在request域中添加数据给视图层

方式一:通过HttpServletRequest放入request 域

@RequestMapping(value = "/show")
public String show(Master master,HttpServletRequest request){
    request.setAttribute("address","tj");
    return "show_info";
}

方式二:通过请求的方法参数 Map<String,Object> 放入 request 域

@RequestMapping(value = "/show")
public String show(Map<String, Object> map, Master master){
    map.put("address","bj");
    return "show_info";
}

方式三:通过返回 ModelAndView 对象实现将数据放入到request域中

@RequestMapping(value = "/show")
public ModelAndView show(Map<String, Object> map, Master master){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("address","sh");
    modelAndView.addObject("master",master);
    modelAndView.setViewName("show_info");
    return modelAndView;
}

视图层通过el表达式显示数据:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>vote_ok </title>
    </head>
    <body>
        <h1>获取的的数据显示页面</h1>
        <hr>
        取出 request 域的数据
        <br>
        address: ${address }<br>
        主人名字= ${requestScope.master.name }
        主人信息= ${requestScope.master }
        宠物名字= ${requestScope.master.pet.name }
    </body>
</html>

5.2 将数据放入session域

通过HttpSession将数据放入session域:

@RequestMapping(value = "/show")
public String show(Master master,HttpSession session){
    session.setAttribute("address","fj");
    session.setAttribute("master",master);
    return "show_info";
}

在视图层通过el表达式取出:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>vote_ok </title>
    </head>
    <body>
        <h1>获取的的数据显示页面</h1>
        <hr>
        取出 session 域的数据
        <br>
        address: ${sessionScope.address }<br>
        主人名字= ${sessionScope.master.name }
        主人信息= ${sessionScope.master }
        宠物名字= ${sessionScope.master.pet.name }
    </body>
</html>

5.3 @ModelAttribute

在某个方法上,增加了@ModelAttribute 注解后,在调用该 Handler 的任何一个方法时,都会先调用这个方法。

@Controller
public class UserServlet {
    @RequestMapping(value = "/login")
    public String login(HttpServletRequest request, HttpServletResponse response){
        return "login_ok";
    }
    
    @RequestMapping(value = "/show")
    public String show(Master master,HttpSession session){
        session.setAttribute("address","fj");
        session.setAttribute("master",master);
        return "show_info";
    }
    @ModelAttribute
    public void prepareMode(){
        System.out.println("前置方法被调用");
    }
}

说明:在调用login()show()方法前都会先调用prepareMode()

应用场景:在修改用户信息前,在前置方法中从数据库查出这个用户,在修改方法(目标方法)中,可以使用前置方法从数据库查询的用户,如果表单中对用户的某个属性修改了,则以新的数据为准,如果没有修改,则以数据库的信息为准,比如,用户的某个属性不能修改,就保持原来的值。

6. 视图和视图解析器

在默认情况下,我们都是返回默认的视图,然后这个返回的视图交由 SpringMVC 的
InternalResourceViewResolver 视图处理器来处理的

applicationContext-mvc.xml:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/pages/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>

6.1 自定义视图实例

1)在applicationContext-mvc.xml中配置自定义视图解析器

</bean>
    <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" >
    <property name="order" value="0"></property>
</bean>

说明:

  • BeanNameViewResolver 这个就是可以解析自定义视图的解析器
  • name=“order” :表示给这个解析器设置优先级, 默认优先级很低值 Integer.MAX_VALUE
  • 一般来说明,我们自己的视图解析优先级高,Order 值越小,优先级越高

2)创建视图类继承AbstractView

@Component(value = "myView")
public class MyView extends AbstractView {

    @Override 
    protected void renderMergedOutputModel(Map<String, Object> map, HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setContentType("text/html");
        response.getWriter().write("<html><body>这是myView</body></html>");
    }
}

3)调用

@RequestMapping(value = "/login")
public String login(HttpServletRequest request, HttpServletResponse response){
    return "myView";
}

7. 数据格式化

在我们提交数据时,基本数据类型可以和字符串之间自动完成转换

示例:将表单请求的字符串数据转化成java数据类型

1)创建Matster.java用来接收数据

public class Master {
    private Integer id;
    private String name;
    private Pet pet;
    public Pet getPet() {
        return pet;
    }
    public void setPet(Pet pet) {
        this.pet = pet;
    }
    public Master() {
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Master{" +"id=" + id +
            ", name='" + name + '\'' +
            ", pet=" + pet +
            '}';
    }
}

2)创建入口界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>add</title>
</head>
<body>
<a href="show">添加master</a>
</body>
</html>

3)跳转到添加界面

@RequestMapping(value = "/show")
public String show(Master master){
    return "show_info";
}

4)在添加界面中使用spring提供的form标签封装数据

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
    <head>
        <title>vote_ok </title>
    </head>
    <body>
        <form:form action="save" method="POST" modelAttribute="master">
            id: <form:input path="id"/> <br><br>
            姓名~: <form:input path="name"/> <br><br>
            宠物id: <form:input path="pet.id"/> <br><br>
            宠物名称: <form:input path="pet.name"/> <br><br>
            <input type="submit" value="添加"/>
        </form:form>
    </body>
</html>

5)接收传递来的数据,跳转到成功界面

@RequestMapping(value = "/save")
public String save(Master master){
    System.out.println(master);
    return "success";
}

6)success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h1>添加成功</h1>
    </body>
</html>

若要完成字符串与特殊数据类型的转换可以使用相应注解,在传递数据时也需要按相应格式传递,否则无法接收

@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birthday;

@NumberFormat(pattern="###,###.##")
private float salary;

8. 数据验证

对输入的数据(比如表单数据),可以进行必要的验证,并给出相应的提示信息。

对于验证表单数据,springMVC 提供了很多实用的注解,这些注解由 JSR 303 验证框架提供

JSR 303 提供的基本验证注解有:

请添加图片描述

Hibernate Validator 是 JSR 303 实现的一个扩展,扩展注解有如下:

请添加图片描述

示例:

1)导入依赖

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.6.Final</version>
</dependency>
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>

2)配置validator

<mvc:annotation-driven validator="validator"/>

3)给需要验证的字段添加注解

public class Master {
    @Range(min = 1,max = 100)
    @NotNull
    private Integer id;

    @NotEmpty
    private String name;

    @Email
    private String eamil;

    private Date birthday;

    @NotNull
    private float salary;

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public float getSalary() {
        return salary;
    }

    public void setSalary(float salary) {
        this.salary = salary;
    }

    public String getEamil() {
        return eamil;
    }

    public void setEamil(String eamil) {
        this.eamil = eamil;
    }


    public Master(Integer id, String name, String eamil, Date birthday, float salary, Pet pet) {
        this.id = id;
        this.name = name;
        this.eamil = eamil;
        this.birthday = birthday;
        this.salary = salary;
    }

    public Master() {
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }


    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Master{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", eamil='" + eamil + '\'' +
                ", birthday=" + birthday +
                ", salary=" + salary +
                '}';
    }
}

4)在handler中用@Valid注解对数据进行验证,并用Errors和map接收验证信息

@RequestMapping(value = "/save")
public String save(@Valid Master master, Errors errors, Map<String, Object> map){
    System.out.println(master);
    System.out.println(errors);
    System.out.println(map);
    if(errors.hasErrors()){
        return "show_info";
    }
    return "success";
}

8.1 自定义错误信息

1)配置xml

<!-- 配置国际化文件名字
如果你这样配的话,表示 messageSource 回到 src/i18nXXX.properties 去读取错误信息
-->
<bean id="messageSource" class=
      "org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basename" value="i18n"></property>
</bean>

2)在resources目录下创建i18n.properties文件

NotEmpty.master.name=\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a
typeMismatch.master.id=\u5e74\u9f84\u8981\u6c42\u5728\u0031\u002d\u0031\u0035\
u0030\u4e4b\u95f4

8.2 取消数据绑定

在默认情况下,表单提交的数据都会和 pojo 类型的 javabean 属性绑定,如果程序员在开发中,希望取消某个属性的绑定,也就是说,不希望接收到某个表单对应的属性的值,则可以通过 @InitBinder 注解取消绑定。

在handler中添加方法:

//取消绑定 master 的 name 表单提交的值给 monster.name 属性
@InitBinder
public void initBinder(WebDataBinder dataBinder) {
 dataBinder.setDisallowedFields("name");
}

9. 中文乱码处理

我们可以使用过滤器来解决中文乱码问题。

自定义中文乱码过滤器:

public class MyCharacterFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse
                         servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 设置字符编码
        servletRequest.setCharacterEncoding("utf-8");
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void destroy() {
    }
}

在web.xml文件中配置过滤器:

<filter>
    <filter-name>myCharacterFilter</filter-name>
    <filter-class>com.lhs.filter.MyCharacterFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>myCharacterFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

10. 处理 json 数据

在前后端分离的项目中,我们一般需要将数据以json格式返回,这时我们可以使用@ResponseBody注解表示返回Json数据。

同理,在接收Json数据时我们也需要在参数前添加@RquestBody注解。

我们可以将@ResponseBody注解写在类上,使其对所有方法生效。

可以用@RestController注解来替代@ResponseBody + @Controller 两个注解

返回Json数据示例:

1)创建jsp界面,发出请求

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>json 提交</title>
        <!-- 引入 jquery -->
        <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
        <!-- 编写 jquery 代码和请求 -->
        <script type="text/javascript">
            $(function () {
                //绑定超链接点击事件
                $("#getJson").click(function () {
                    //href 是一个完整的请求地址
                    var href = this.href;
                    alert(href);
                    var args = {"time": new Date()};//防止缓存
                    //发出一个 jquery 的 post 请求,请求返回 json
                    $.post(href, args, function (data) {
                        alert(" name= " + data.name + " address= " + data.address);
                        //1. data 是 json 对象
                        //2. JSON.stringify(data) 是将 json 对象转成字符串
                        alert("返回数据 json=" + data)
                        alert("返回数据 json=" + JSON.stringify(data))
                    }, "json");
                    //防止重复提交
                    return false;
                })
            })
        </script>
    </head>
    <body>
        <h1>请求一个 json 数据</h1>
        <a href="getJson" id="getJson">点击获取 json 数据</a>
    </body>
</html>

2)返回json数据

@RequestMapping("getJson")
@ResponseBody // 表示返回的数据为Json格式
public Master getJson(){
    Master master = new Master(1,"lxg","123@qq.com",11.1f);
    return master;
}

接收Json数据示例:

1 )修改jsp文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<!-- 编写 jquery 代码和请求 -->
<script>
    $(function (){
        //绑定超链接点击事件
        $("#getJson").click(function () {
            //href 是一个完整的请求地址
            var href = this.href;
            alert(href);
            var args = {"time": new Date()};//防止缓存
            //发出一个 jquery 的 post 请求,请求返回 json
            $.post(href, args, function (data) {
                alert(" name= " + data.name + " address= " + data.address);
                //1. data 是 json 对象
                //2. JSON.stringify(data) 是将 json 对象转成字符串
                alert("返回数据 json=" + data)
                alert("返回数据 json=" + JSON.stringify(data))
            }, "json");
            //防止重复提交
            return false;
        })
        $("button[name='butt1']").click(function () {
            var userName = $("#userName").val()
            var age = $("#age").val()
            $.ajax({
                url: "/springmvc/save2",
                data: JSON.stringify({"username": userName, "age": age}),
                type: "POST",
                success:
                    function (data) {
                    alert("返回的信息=" + JSON.stringify(data));
                },
                contentType: "application/json;charset=utf-8"
            });
        })
    })

</script>
</head>
<body>
    <h1>请求一个 json 数据</h1>
    <a href="getJson" id="getJson">点击获取 json 数据</a>
    <h1>发出一个 json 数据</h1>
    u:<input id="userName" type="text"><br/>
    a:<input id="age" type="text"><br/>
    <button name="butt1">添加用户</button>
</body>
</html>

2)接收json数据

@RequestMapping("save2")
@ResponseBody
public User save2(@RequestBody User user){
    System.out.println(user);
    return user;
}

11. HttpMessageConverter<T>

SpringMVC 处理 JSON-底层实现是依靠 HttpMessageConverter来进行转换的

当控制器处理方法使用到 @RequestBody/@ResponseBody 或 HttpEntity/ResponseEntity 时,Spring 首先根据请求头或响应头的 Accept 属性选择匹配 的 HttpMessageConverter,进而根据参数类型或泛型类型的过滤得 到匹配 的HttpMessageConverter, 若找不到可用的 HttpMessageConverter 将报错

请添加图片描述

12. 文件上传

Spring MVC 为文件上传提供了直接的支持 , 这种支持是通过即插即用的 MultipartResolver 实现的 。

示例:

1)导入依赖

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.5</version>
</dependency>

2)Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需现在上下文中配置 MultipartResolver:

<bean id="multipartResolver" 
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>

3)创建jsp界面,上传图片

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>文件上传</title>
    </head>
    <body>
        <h1>文件上传的演示</h1>
        <form action="fileUpload" method="post" enctype="multipart/form-data">
            文件介绍:<input type="text" name="introduce"><br>
            选择文件:<input type="file" name="file"><br>
            <input type="submit" value="上传文件">
        </form>
    </body>
</html>

4)handler中接收上传的图片

@RequestMapping(value="/fileUpload")
public String fileUpload(@RequestParam(value="file") MultipartFile file, HttpServletRequest request)
    throws Exception {
    String originalFilename = file.getOriginalFilename();
    System.out.println("上传文件名= " + originalFilename);
    String filepath = "E:\\javaProject\\SpringMVCDemo\\web\\images\\" + originalFilename;
    File saveToFile = new File(filepath);
    file.transferTo(saveToFile);
    return "success";
}

13. 自定义拦截器

Spring MVC 也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能

自定义的拦截器必须实现 HandlerInterceptor 接口

自定义拦截器的三个方法:

  • preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求request 进行处理。
  • postHandle():这个方法在目标方法处理完请求后执行
  • afterCompletion():这个方法在完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。

自定义拦截器执行流程说明:

  • 如果 preHandle 方法 返回 false,则不再执行目标方法,可以在此指定返回页面
  • postHandle 在目标方法被执行后执行,可以在方法中访问到目标方法返回的ModelAndView 对象
  • 若 preHandle 返回 true,则 afterCompletion 方法在渲染视图之后被执行
  • 若 preHandle 返回 false,则 afterCompletion 方法不会被调用
  • 在配置拦截器时,可以指定该拦截器对哪些请求生效,哪些请求不生效

示例:

1)创建拦截器

@Component
public class MyInterceptor01 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        // System.out.println("preHandle.....");
        // String mess = "炸弹";
        // if(mess.equals("炸弹")){
        // //返回到一个警告页面
        // arg0.getRequestDispatcher("/WEB-INF/pages/warning.jsp").forward(arg0, arg1);
        // return false;
        // }else{
        // return true;
        // }
        System.out.println("===MyInterceptor01 preHandle()===");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
        System.out.println("===MyInterceptor01 postHandle()===");
    }

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
        System.out.println("===MyInterceptor01 afterCompletion()===");
    }
}

2)在spring的配置文件中配置拦截器

<mvc:interceptors>
    <mvc:interceptor>
        <!--  配置匹配规则-->
        <mvc:mapping path="/h*"/> 
        <!--  配置需要排除的路径-->
        <mvc:exclude-mapping path="/hello"/>
        <ref bean="myInterceptor01"/>
    </mvc:interceptor>
</mvc:interceptors>

14. 异常处理

Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。

我们可以自定义异常处理方式,若未设置,当服务器发生异常时,默认的异常处理机制会返回一个状态码为500的界面。

14.1 局部异常

//局部异常就是直接在这个 Handler 中编写即可
@ExceptionHandler({ArithmeticException.class,NullPointerException.class})
public String localException(Exception ex, HttpServletRequest request){
    System.out.println("异常信息是~" + ex.getMessage());
    //将异常的信息带到下一个页面
    request.setAttribute("reason", ex.getMessage());
    return "exception_mes";

14.2 全局异常

ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,会找 @ControllerAdvice 类的@ExceptionHandler 注解方法,这样就相当于一个全局异常处理器。

@ControllerAdvice
public class MyGlobalException {
    //全局异常就不管是哪个 Handler 抛出的异常,都可以捕获
    @ExceptionHandler({ClassCastException.class, NumberFormatException.class})
    public String localException(Exception ex, HttpServletRequest request) {
        System.out.println("全局异常信息是= " + ex.getMessage());
        request.setAttribute("reason", ex.getMessage());
        //将异常的信息带到下一个页面. 
        return "exception_mes";
    }
}

14.3 SimpleMappingExceptionResolver

如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。

示例:对数组越界异常进行统一处理

//统一的异常
@RequestMapping(value="/testException03")
public String test03(){
    int[] arr = new int[]{3,9,10,190};
    System.out.println(arr[90]);
    return "success";
}

添加统一异常处理的配置:

<bean
      class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.ArrayIndexOutOfBoundsException">arrEx</prop>
            <!--    对未知异常进行处理 -->
            <!--  <prop key="java.lang.Exception">otherEx</prop>  -->
        </props>
    </property>
</bean>

创建/WEB-INF/pages/arrEx.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>数组越界了</title>
    </head>
    <body>
        <h1>数组越界了~</h1>
    </body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林小果呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值