SpringMVC请求、响应和拦截器的使用

SpringMVC请求

RequestMapping注解

RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
RequestMapping注解可以作用在方法和类上

java 复制代码
1. 作用在类上:第一级的访问目录
2. 作用在方法上:第二级的访问目录
3. 细节:路径可以不编写 / 表示应用的根目录开始

(1).RequestMapping的属性

java 复制代码
1. path 指定请求路径的url
2. value value属性和path属性是一样的
3. mthod 指定该方法的请求方式
java 复制代码
@Controller
@RequestMapping(path = "/role") // 一级请求路径
public class RoleController {
    /**
     * /role/save
     * method="当前方法允许请求方式能访问"
     * params="请求路径上传参数"
     * @return
     */
   @RequestMapping(path = "/save",method = {RequestMethod.GET})
    public String save(){
        System.out.println("保存角色...");
        return "suc";
    }

    @RequestMapping(value = "/delete")
    public String delete(){
        System.out.println("删除角色...");
        return "suc";
    }
}

(2).RequestMapping的请求参数绑定

1. 绑定机制
  1. 表单提交的数据都是k=v格式的 username=haha&password=123
  2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
  3. 要求:提交表单的name和参数的名称是相同的
2. 支持的数据类型
  1. 基本数据类型和字符串类型
  2. 实体类型(JavaBean)
  3. 集合数据类型(List、map集合等)

基本数据类型和字符串类型

  1. 提交表单的name和参数的名称是相同的
  2. 区分大小写

实体类型(JavaBean)

  1. 提交表单的name和JavaBean中的属性名称需要一致
  2. 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:address.name

给集合属性数据封装

JSP页面编写方式:list[0].属性

jsp代码

java 复制代码
<html>
<head>
    <meta charset="utf-8">
    <title>入门程序</title>
</head>
<body>
<h3>入门</h3><a href="/SpringMVC/hello" >入门程序</a>
    <h1>请求参数绑定入门程序</h1>
    <form action="/SpringMVC/user/save" method="get">
        <input type="text" name="username"/><br/>
        <input type="text" name="age"/><br/>
        <input type="submit"/>
    </form>
    <h1>请求参数绑定入门程序(封装到实体类)</h1>
    <form action="/user/save1" method="post">
        <input type="text" name="username"/><br/>
        <input type="text" name="age"/><br/>
        <input type="submit"/>
    </form>
    <h1>请求参数绑定入门程序(封装到实体类)</h1>
    <form action="/user/save2" method="post">
        <input type="text" name="username"/><br/>
        <input type="text" name="age"/><br/>
        <input type="text" name="account.money"/><br/>
        <input type="submit"/>
    </form>
    <h1>请求参数绑定入门程序(存在list集合)</h1>
    <form action="/user/save3" method="post">
        <input type="text" name="username"/><br/>
        <input type="text" name="age"/><br/>
        <input type="text" name="account.money"/><br/>
        <input type="text" name="accounts[0].money"/><br/>
        <input type="text" name="accounts[1].money"/><br/>
        <input type="submit"/>
    </form>
</body>
</html>

JavaBean代码

java 复制代码
public class Account {
    private Double money;

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "money=" + money +
                '}';
    }
}
java 复制代码
public class User {
    private String username;
    private Integer age;
    private Account account;
    private List<Account> accounts;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", account=" + account +
                ", accounts=" + accounts +
                '}';
    }
}

controller代码

java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/save")
    public String save(String username,Integer age){
        System.out.println(username);
        System.out.println(age);
        return "suc";
    }

    @RequestMapping("/save1")
    public String save1(User user){
        System.out.println(user.toString());
        return "suc";
    }

    @RequestMapping("/save2")
    public String save2(User user){
        System.out.println(user);
        return "suc";
    }

    @RequestMapping("/save3")
    public String save3(User user){
        System.out.println(user);
        return "suc";
    }

}

在控制器中使用原生的ServletAPI对象

只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象

java 复制代码
@RequestMapping(value = "/save6.do",method = {RequestMethod.POST})
public String save6(HttpServletRequest request, HttpServletResponse response){
    // 获取到HttpSession对象
    System.out.println(request.getParameter("username"));
    HttpSession session = request.getSession();
    System.out.println(session);
    System.out.println(response);
    return "suc";
}

SpringMVC响应

第一章:数据处理及跳转

1. 结果跳转方式

①.ModelAndView

设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面

java 复制代码
<bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
    <property name="prefix" value="/html/" />
    <property name="suffix" value=".html" />
    <property name="templateMode" value="HTML5"/>
</bean>

对应的controller类

java 复制代码
/**
 * 返回ModelAndView对象的方式
 * @return
 */
@RequestMapping("/save3")
public ModelAndView save3(){
    System.out.println("执行了...");
    // 创建mv对象
    ModelAndView mv = new ModelAndView();
    // 把一些数据,存储到mv对象中
    mv.addObject("msg","用户名或者密码已经存在");
    // 设置逻辑视图的名称
    mv.setViewName("suc");
    return mv;
}
②.ServletAPI

通过设置ServletAPI , 不需要视图解析器 .

1、通过HttpServletResponse进行输出

2、通过HttpServletResponse实现重定向

3、通过HttpServletResponse实现转发

java 复制代码
@Controller
@RequestMapping(path = "/role") // 一级请求路径
public class RoleController {

    @RequestMapping("/t1")
    public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
        rsp.getWriter().println("Hello,Spring BY servlet API");
    }

    @RequestMapping("/t2")
    public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
        rsp.sendRedirect("/SpringMVCDemo/html/suc.html");
    }

    @RequestMapping("/t3")
    public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
        //转发
        req.setAttribute("msg","hello");
        req.getRequestDispatcher("/html/suc.html").forward(req,rsp);
    }

}
③.SpringMVC

通过SpringMVC来实现转发和重定向 - 无需视图解析器;
测试前,需要将视图解析器注释掉

java 复制代码
@Controller
@RequestMapping(path = "/role") // 一级请求路径
public class RoleController {

    @RequestMapping("/t1")
    public String test1(){
        //转发
        return "/html/suc.html";
    }

    @RequestMapping("/t2")
    public String test2(){
        //转发二
        return "forward:/html/suc.html";
    }

    @RequestMapping("/t3")
    public String test3(){
        //重定向
        return "redirect:/html/suc.html";
    }

}

2.ResponseBody响应json数据

json和JavaBean对象互相转换的过程中,需要使用jackson的jar包

java 复制代码
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.0</version>
</dependency>

DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置

标签配置不过滤

  1. location元素表示webapp目录下的包下的所有文件
  2. mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
java 复制代码
<!--设置静态资源不过滤-->
<mvc:resources mapping="/css/**" location="/css/"/> <!--样式-->
<mvc:resources mapping="/images/**" location="/images/"/> <!--图片-->
<mvc:resources mapping="/js/**" location="/js/"/> <!--javascript-->

html代码

java 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
    <script>
        // 页面加载
        $(function(){
            // 单击事件
            $("#btn").click(function(){
            // 发送ajax的请求
                $.ajax({
                    type: "post",
                    url: "/SpringMVCDemo/user/save6",
                    data:{username:"haha",age:"20"},
                    success:function(d){
                        // 编写很多代码
                        alert(d.username+" ‐ "+d.age);
                    }
                });
            });
        });
    </script>
</head>
<body>
<h3>异步的数据交互</h3>
<input type="button" value="ajax交互" id="btn">
</body>
</html>

controller

java 复制代码
/**
 * 异步的数据交互
 * 重定向
 * @return
 */
@RequestMapping("/save6")
public @ResponseBody User save6(User user){
    System.out.println(user);
    // 模拟,调用业务层代码
    user.setUsername("hello");
    user.setAge(100);
    // 把user对象转换成json,字符串,再响应。使用@ResposeBody注解 response.getWriter().print()
    return user;
}

在springMVC当中如果要实现页面跳转就不要使用ajax,如果要json数据的返回就用ajax

第二章:SpringMVC实现文件上传

导入文件上传的jar包

java 复制代码
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.4</version>
</dependency>

在Springmvc.xml配置文件上传解析器

java 复制代码
<!--配置文件上传的解析器组件。id的名称是固定,不能乱写-->
 <bean id="multipartResolver"
       class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
 <!--设置上传文件的总大小 8M = 8 * 1024 * 1024 -->
 <property name="maxUploadSize" value="8388608" />
 </bean>

编写文件上传的html页面

java 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>文件上传</h3>

<form id="addForm"  action="/SpringMvc/file/upload" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="file" width="120px">
    <input type="submit" value="上传">
</form>

<div id="upMenu" class="white_content">
    <form id="downForm"   lay-filter="updata" action="/SpringMvc/file/down" method="get">
        <input type="text" id="filename" name="filename">
        <input type="submit" value="下载">
    </form>
    <input type="button" value="完成"/>
</div>

</body>
</html>

controller层

java 复制代码
@Controller
@RequestMapping("/file")
public class FileController {


    /**
     * 文件上传功能
     * @param file
     * @return
     * @throws IOException
     */
    @RequestMapping(value="/upload",method= RequestMethod.POST)
    @ResponseBody
    public  String upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
        // uploads文件夹位置
        String rootPath = request.getSession().getServletContext().getRealPath("WEB-INF/upload");
        // 原始名称
        String originalFileName = file.getOriginalFilename();
        // 新文件
        File newFile = new File(rootPath + File.separator  + File.separator + originalFileName);
        // 判断目标文件所在目录是否存在
        if( !newFile.getParentFile().exists()) {
            // 如果目标文件所在的目录不存在,则创建父目录
            newFile.getParentFile().mkdirs();
        }
        System.out.println(newFile);
        // 将内存中的数据写入磁盘
        file.transferTo(newFile);
        return  "{\"data\":\"success\"}";
    }

    /**
     * 文件下载功能
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/down")
    public void down(HttpServletRequest request, HttpServletResponse response) throws Exception{
        String filename = request.getParameter("filename");
        System.out.println(filename);
        //模拟文件,myfile.txt为需要下载的文件
        String fileName = request.getSession().getServletContext().getRealPath("WEB-INF/upload")+"/"+filename;
        //获取输入流
        InputStream bis = new BufferedInputStream(new FileInputStream(new File(fileName)));
        //假如以中文名下载的话
       // String filename = "下载文件.txt";
        //转码,免得文件名中文乱码
        filename = URLEncoder.encode(filename,"UTF-8");
        //设置文件下载头
        response.addHeader("Content-Disposition", "attachment;filename=" + filename);
        //1.设置文件ContentType类型,这样设置,会自动判断下载文件类型
        response.setContentType("multipart/form-data");
        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        int len = 0;
        while((len = bis.read()) != -1){
            out.write(len);
            out.flush();
        }
        out.close();
    }
}

第三章:SpringMVC的异常处理

1. 异常处理思路

Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理。

2. SpringMVC的异常处理

①:使用自己处理异常

controller代码

java 复制代码
/**
 * 自己处理异常
 * @return
 */
@RequestMapping("/findAll")
public String findAll(Model model){
    try {
        System.out.println("执行了...");
        // 模拟异常
        int a = 10/0;
    }catch (Exception e){
        model.addAttribute("errorMsg","系统正在维护,请联系管理员");
        return "404";
    }
    return "suc";
}

404页面

java 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>错误提示页面</title>
</head>
<body>
<h1>404  <b th:text="${errorMsg}"></b></h1>
</body>
</html>

②:使用处理器处理异常

controller代码

java 复制代码
/**
 * 使用异常处理器方式
 * @return
 */
@RequestMapping("/findAll2")
public String findAll2(){
    System.out.println("执行了...");
    //模拟异常
    int a = 10 / 0;
    return "suc";
}

自定义异常类

java 复制代码
public class SysException extends Exception{
    // 提示消息
    private String message;

    public SysException(String message){
        this.message = message;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "SysException{" +
                "message='" + message + '\'' +
                '}';
    }
}

配置异常处理器

java 复制代码
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="com.qcby.conf.SysExceptionResolver" />

SpringMVC拦截器

1.什么是拦截器

SpringMVC提供了Intercepter拦截器机制,类似于Servlet当中的Filter过滤器,用于拦截用户的请求并作出相应的处理,比如通过拦截器来进行用户权限验证或者用来判断用户是否登录。

SpringMVC拦截器是可插拔式的设计,需要某一功能拦截器,就需要在配置文件中应用拦截器即可;如果不需要这个功能拦截器,只需要在配置文件中取消该拦截器即可。

2.拦截器和过滤器有哪些区别

1.过滤器依赖于servlet,而拦截器技术属于SpringMVC

2.过滤器可对所有请求起作用,拦截器只对访问controller层的请求起作用。

3.过滤器会比拦截器先执行。拦截器(Interceptor)是在Servlet和Controller控制器之间执行;而过滤器(Filter)是在请求进入Tomcat容器之后 但是在请求进入Servlet之前执行。

3.拦截器方法

想要自定义拦截器,需要实现HandlerInterceptor接口。

我们可以看到 HandlerInterceptor接口有三个方法,分别是preHandle、postHandle、afterCompletion,关于这三个方法

  • preHandle 方法: 该方法在执行器方法之前执行。返回值为Boolean类型,如果返回false,表示拦截,不再向下执行;如果返回true,表示放行,程序向下执行(如果后边没有其他Interceptor,就会执行Controller方法)。所以,此方法可对方法进行判断,决定程序是否继续执行,或者进行一些初始化操作及对请求进行预处理。
  • postHandle方法: 该方法在执行控制器方法调用之后,且在返回ModelAndView之前执行。由于该方法会在DispatcherServlet进行返回视图渲染之前被调用,所以此方法多被用于处理返回的视图, 可通过此方法多被用于处理返回的视图,可通过此方法对请求域中的模型和视图做进一步的修改。
  • afterCompletion方法: 该方法在执行完控制器之后执行。由于是在Controller方法执行完毕之后执行该方法,所以该方法适合进行一些资源清理、记录日志信息等处理操作。

4.单个拦截器的执行流程

程序首先会执行拦截器类中的preHandle()方法,如果该方法的返回值true,则程序继续向下执行处理器当中的方法,否则不在向下执行;业务处理器(即控制器Controller类)处理完请求后,会执行postHandle()方法,然后会通过DispatcherServlet向前端返回响应;在DispatcherServlet处理完请求后,才会执行afterCompletion()方法。

5.使用拦截器实现用户登录权限验证


Controller层的设计

java 复制代码
@Controller
public class LoginController {

    /**
     * 跳转登录页
     * @return
     */
    @RequestMapping(value = "/login",method = RequestMethod.GET)
    public String loginPage(){
        System.out.println("跳转到login.html页面当中");
        return "login";
    }

    /**
     * 用户登录,成功到主页,失败回到登录页
     * @param user
     * @param model
     * @param session
     * @return
     */
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(User user, Model model, HttpSession session){
        if(user.getUsername() !=null && user.getUsername().equals("admin")
                && user.getPassword() !=null && user.getPassword().equals("123456")){
            System.out.println("用户登录功能实现");
            //将用户添加到session保存
            session.setAttribute("user",user);
            return "/suc";
        }
        model.addAttribute("msg","账户或密码错误,请重新登录");
        return "login";
    }

    /**
     * 跳转到主页
     * @return
     */
    @RequestMapping("/index")
    public String indexPage(){
        System.out.println("跳转到主页");
        return "suc";
    }

    /**
     * 用户退出登录
     * @param session
     * @return
     */
    @RequestMapping("/logout")
    public String logout(HttpSession session){
        session.invalidate();//清除session
        System.out.println("用户退出登录");
        return "login";
    }

}

登录页面

java 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h1> <font color="red"> <b th:text="${msg}"></b></font></h1>
<form action="/SSMDemo/login" method="post">
    账户:<input type="text" name="username"/>
    密码:<input type="password" name="password"/>
    <input type="submit" value="登录"/>
</form>
</body>
</html>

主页

java 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>Hello <b th:text="${msg}"></b></h1>
<a href="/SSMDemo/logout" >入门程序</a>
</body>
</html>

拦截器配置

java 复制代码
/**
 * 登录拦截器
 */
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取请求url
        String url = request.getRequestURI();
        //非登录请求进行拦截
        if (!url.contains("login")){
            //非登录请求获取session
            if(request.getSession().getAttribute("user") != null){
                return true;//说明已经登录,放行
            }else { //没有登录,跳转到登录页面
                request.setAttribute("msg","您还没登录。请先登录。。。");
                request.getRequestDispatcher("/html/login.html").forward(request,response);
            }
        }else {
            return true; //登录请求,放行
        }
        return true;
    }
    
    //省略了postHandle()和afterCompletion()方法
}

在springMV.xml文件当中配置拦截器

xml 复制代码
<!--配置拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/> <!--/**表示所有url-->
        <bean class="com.qcby.Interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

6.多个拦截器的执行流程

当多个拦截器同时工作时,它们的preHandle()方法会按照配置文件中拦截器的配置顺序执行,而它们的postHandle()方法和afterCompletion()方法则会按照配置顺序的反序执行。

假设有两个拦截器Interceptor1和interceptor2,并且在配置文件中,Interceptor1拦截器配置在前。

相关推荐
Mr.Java.8 分钟前
Spring Boot MongoDB自定义连接池配置
java·spring boot·后端·mongodb
JIngJaneIL22 分钟前
健身管理小程序|基于java微信开发健身管理小程序的系统设计与实现(源码+数据库+文档)
java·数据库·小程序·vue·毕业设计·论文·健身管理小程序
菠萝崽.37 分钟前
springboot中测试python脚本:ProcessBuilder
java·开发语言·spring boot·python·processbuilder
哪吒编程1 小时前
从0.031秒优化0.018秒,JEP 483为Java应用带来的启动加速黑科技
java·后端
努力的搬砖人.1 小时前
nacos配置达梦数据库驱动源代码步骤
java·服务器·数据库·经验分享·后端
朱啸毅1 小时前
Tomcat
java·tomcat
风象南1 小时前
SpringBoot中3种条件装配技术
java·spring boot·后端
Java小白中的菜鸟1 小时前
深入理解Java反射
java·开发语言
自由与自然1 小时前
乐观锁与悲观锁的使用场景
java·服务器·数据库
爱的叹息4 小时前
spring mvc 中 RestTemplate 全面详解及示例
java·spring·mvc