详解Spring MVC页面跳转,数据存储,异步交互,RESTfull风格,拦截器,文件的上传与下载

Spring MVC

SpringMVC页面跳转

请求转发

简单方式
@RequestMapping("/quick")
public String quick(){
    return "success" ;
}

该方法直接返回一个字符串,其底层用的就是请求转发
这种写法会走配置文件中的视图解析器,但是有一个问题,如果我们跳转到配置的路径以外的页面,就会有问题,访问不到。这个时候我们就需要用到第二种forward方式 了!

forward关键字

forward关键字的底层是:request.getRequestDispatcher("/跳转路径").forward(req,resp);
使用forward关键字,不在经过试图解析器进行拼接字符串

编写index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/forward/forward01">基本的请求转发</a><br>
<a href="/forward/forward02">请求转发</a><br>
<a href="/redirect">重定向</a><br>
<a href="/modelAndView">modelAndView存储数据</a><br>
<a href="/model">model存储数据</a>
</body>
</html>

编写controller
@Controller
@RequestMapping("/forward")
public class ForwardController {

    /**
     * 最简单的转发方式
     * @return
     */
    @RequestMapping("/forward01")
    public String forward01(){
        return "success";
    }

    @RequestMapping("/forward02")
    public String forward02(){
//        return "forward:/list.jsp";
        return "list";
    }
}
在根目录下编写list.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>list页面</h3>
${name}
</body>
</html>
servlet原生API

原生API就是用原来的HttpServletRequest和HttpServletResponse来完成页面跳转,这种方式实际开发中不用,大家了解一下即可!

编写index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <a href="${pageContext.request.contextPath}/servletApi">原生API</a>
    </body>
</html>
编写controller
    @RequestMapping("/servletApi")
        public void servletApi(HttpServletRequest request, 
                               HttpServletResponse response,
                                        HttpSession session) throws Exception {
       request.getRequestDispatcher("/list.jsp").forward(request,response);
    }

重定向

redirect关键字

此关键字的底层:response.sendRedirect(“web项目地址+重定向地址”);
而且还在此技术上进行了优化,我们不需要再去编写web项目地址,直接编写重定向地址

编写index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/forward/forward01">基本的请求转发</a><br>
<a href="/forward/forward02">请求转发</a><br>
<a href="/redirect">重定向</a><br>
<a href="/modelAndView">modelAndView存储数据</a><br>
<a href="/model">model存储数据</a>
</body>
</html>
编写controller
@RequestMapping("/redirect")
public String redirect()  {
    return "redirect:/list.jsp";
}
servlet原生API
编写index.jsp页面

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

        <a href="${pageContext.request.contextPath}/sendRedirect">原生API重定向</a>
        
    </body>
</html>

编写controller

@RequestMapping("/sendRedirect")
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
    response.sendRedirect(request.getContextPath()+"/list.jsp");
}

SrpingMVC存储数据

原生ServletAPI

编写index.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <a href="${pageContext.request.contextPath}/requestAPI">原生request存储数据</a>
    </body>
</html>

编写controller
@RequestMapping("/requestAPI")
    public void requestAPI(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
        request.setAttribute("name", "小泽");
        request.getRequestDispatcher("/list.jsp").forward(request, response);
}
编写list.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        list页面
        ${name}
    </body>
</html>

ModelAndView存数数据

使用ModelAndView类用来存储处理完后的结果数据,以及显示该数据的视图
其常用方法有
ModelAndView addObject(String attributeName,Object attributeValue)
添加模型数据,相当于key-value的形式
void setViewName(String viewName) 设置视图,要跳转的页面

使用步骤

编写index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/forward/forward01">基本的请求转发</a><br>
<a href="/forward/forward02">请求转发</a><br>
<a href="/redirect">重定向</a><br>
<a href="/modelAndView">modelAndView存储数据</a><br>
<a href="/model">model存储数据</a>
</body>
</html>
编写controller
   @RequestMapping("modelAndView")
    public ModelAndView modelAndView(ModelAndView modelAndView){
        //设置数据
        modelAndView.addObject("name", "小玛");
        //设置视图
        modelAndView.setViewName("list");
        return modelAndView;
    }
编写list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>list页面</h3>
${name}
</body>
</html>

ModelAndView会走配置文件中的视图解析器,要跳转的页面必须是在配置的视图的路径下面,否则404找不到页面!

Model存储数据

使用ModelAndView进行数据的的存储和页面的跳转比较麻烦.SpringMVC单独抽取一个类Model.来进行存值.Model只能存值,不能进行视图的跳转.
常用方法
model.addAttribute(String name,Object o)设置数据key-value形式

使用步骤

编写index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/forward/forward01">基本的请求转发</a><br>
<a href="/forward/forward02">请求转发</a><br>
<a href="/redirect">重定向</a><br>
<a href="/modelAndView">modelAndView存储数据</a><br>
<a href="/model">model存储数据</a>
</body>
</html>

编写controller
   @RequestMapping("/model")
    public String model(Model model){
        model.addAttribute("name","小明");
        return "list";
    }
编写list.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        list页面
        ${name}
    </body>
</html>

SpringMVC异步交互

我们学习完SpringMVC之后,就不用像之前那么麻烦了,还要创建ObjectMapper对象来转换成josn数据进行响应。
SpringMVC已经帮我们做这些事情了。SpringMVC提供了两个注解@RequestBody和@ResponseBody实现josn数据的转换
SpringMVC默认用MappingJackson2HttpMessageConverter对json数据进行转换,需要加入jackson的包

<!--jsckson -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.9</version>
</dependency>

@RequestBody

用于接收前端请求体中的json数据,使用@RequestBody注解就可以自动的封装指定的对象中

行动起来

编写前端代码

使用Ajax发送请求,需要先导入jquery.js
Ajax提交的数据必须是一个标准的json字符串
Ajax提交的方式必须为post,数据必须在请求体中
Ajax提交的MIME类型必须为:application/json;charset=utf-8

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>异步交互</title>
    <script src="/js/jquery-3.3.1.js" type="text/javascript"></script>
</head>
<body>
<button id="ajaxBtn">发送Ajax请求</button>
<script type="text/javascript">
    $(function () {
            $('#ajaxBtn').click(function () {

                $.ajax({
                    //url: '${pageContext.request.contextPath}/ajaxRequest',
                    url:'/mvcAjaxRequest',
                    type: 'POST',
                    data: '{"username":"张三","age":18}',
                    contentType:'application/json;charset=utf-8',
                    success: function (resp) {

                    }
                });
            })
        }
    );
</script>
</body>
设置配置
  1. web.xml配置
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>
  1. spring-mvc.xml配置
<!--
    静态资源手动映射
        mapping="/img/**" 浏览器发送请求
        location="/img/" 静态资源的路径
-->
<mvc:resources mapping="/img/**" location="/img/" />
<mvc:resources mapping="/js/**" location="/js/" />  
<mvc:resources mapping="/css/**" location="/css/"/>
  1. spring-nvc.xml简化配置
<!--配置tomcat默认的静态资源处理-->
<mvc:default-servlet-handler/>
编写实体类
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    private String username;
    private Integer age;
}
编写controller
    /**
     * 通过ObjectMapper转换为json数据
     * @param json
     * @throws IOException
     */
    @RequestMapping("/ajaxRequest")
    public void ajaxRequest(@RequestBody String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        User user = mapper.readValue(json,User.class);
        System.out.println(user);
    }
/**
     * mvc自动转换
     * @param user
     */
    @RequestMapping("/mvcAjaxRequest")
    public void mvcAjaxRequest(@RequestBody User user){
        System.out.println(user);
    }

@RequestBody

用于将controller方法返回的对象通过转换器转换为指定的格式(通常为json)之后,写入到response对象的响应体中。

行动起来

导入jq文件
<script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script>
编写ajax代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>异步交互</title>
    <script src="/js/jquery-3.3.1.js" type="text/javascript"></script>
</head>
<body>
<button id="ajaxBtn">发送Ajax请求</button>
<script type="text/javascript">
    $(function () {
            $('#ajaxBtn').click(function () {

                $.ajax({
                    url:'/mvcAjaxResponse',
                    type: 'POST',
                    data: '',
                    contentType:'application/json;charset=utf-8',
                    success: function (resp) {
                        alert(resp.username);
                        alert(resp.age);
                    }
                });
            })
        }
    );
</script>
</body>
编写controller
   /**
     * mvc自动转换
     * @ResponseBody将对象转为json,再通过response设置到响应体中,返回客户端
     */
    @RequestMapping("/mvcAjaxResponse")
    @ResponseBody
    public User mvcAjaxResponse(){
        User us = new User("赵六", 20);
        return us;
    }

@RequestBody:将请求体中的json字符串,转为指定类型的java对象
@ResponseBody:将java对象转为json字符串,再设置到响应体中,返回到浏览器(客户端)

RESTfull

REST(英文:Representational State Transfer,简称REST,意思:表述性状态转换,描述了一个架构样式的网络系统,比如web应用)。
Restfull就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
应用场景:前后端分离开发的架构中

RESTfull与传统URL对比

传统URL
前端后台描述
http://localhost:8080/user/findAllUsers@RequestMapping(/user/findAllUsers)
public List findAllUsers()
查询所有用户
http://localhost:8080/user/addUser@RequestMapping(/user/addUser)
public void addUser(User user)
添加用户
http://localhost:8080/user/updateUser@RequestMapping(/user/updateUser)
public void updateUser(User user)
修改用户
http://localhost:8080/user/deleteUserById?id=1@RequestMapping(/user/deleteUserById)
public User deleteUserById(int id)
删除用户
RESTfull风格

Restfull风格的请求是使用==“url+请求方式”(名饲+动词)==表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下:

请求方式描述
GET用于获取资源
POST用于新建资源
PUT用于更新资源
DELETE用于删除资源
前端后台描述
http://localhost:8080/user/@RequestMapping(/user,method=GET)
public List findAllUsers()
GET查询所有用户
http://localhost:8080/user/@RequestMapping(/user,method=POST)
public void addUser(User user)
POST添加用户
http://localhost:8080/user/1@RequestMapping(/user/{id},method=PUT)
public void updateUser(@PathVariable int id)
PUT修改id为1用户
http://localhost:8080/user/1@RequestMapping(/user/{id},method=DELETE)
public User deleteUserById(@PathVariable int id)
DELETE删除id为1的用户

上述url地址/user/1中的1就是要获得的请求参数,在SpringMVC中可以使用占位符进行参数绑定。RequestMapping中/user/1可以写成/user/{id},占位符{id}对应的就是1的值。在业务方法中我们可以使用@PathVariable注解进行占位符的匹配获取工作。

RESTfull的使用

定义controller
@Controller
@ResponseBody
public class RestfullController {

    /**
     * 查询所有用户
     * @return
     */
    //@RequestMapping(value = "/findAll",method = RequestMethod.GET)
    //注解形式
    @GetMapping("/findAll")
    public String findAll(){
        return "findAll";
    }

    /**
     * 根据id查询用户
     * @return
     */
    //@RequestMapping(value = "/findById/{id}",method = RequestMethod.GET)
    @GetMapping("/findById/{id}")
    public String findById(@PathVariable Integer id){
        return "findById"+id;
    }

    /**
     * 添加用户
     * @return
     */
    //@RequestMapping(value = "/addUser",method = RequestMethod.POST)
    @PostMapping("/addUser")
    public String addUser(){
        return "adduser";
    }

    /**
     * 根据id修改用户信息
     * @param id
     * @return
     */
    //@RequestMapping(value = "/updateUserById/{id}",method = RequestMethod.PUT)
    @PutMapping("/updateUserById/{id}")
    public String updateUserById(@PathVariable Integer id){
        return "updateUserById"+id;
    }

    /**
     * 根据用户id删除用户信息
     * @param id
     * @return
     */
    //@RequestMapping(value = "/deleteUserById/{id}",method = RequestMethod.DELETE)
    @DeleteMapping("/deleteUserById/{id}")
    public String deleteUserById(@PathVariable Integer id){
        return "deleteUserById"+id;
    }
}

SpringMVC拦截器

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。

拦截器与过滤器的区别

过滤器
servlet规范中的一部分,任何java web工程都可以使用
在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器
拦截器是AOP思想的具体应用。
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的

拦截器的使用

编写目标资源
@Controller
public class TargetController {
    @RequestMapping("/target")
    public String targetResource(){
        System.out.println("执行了目标资源");
        return "success";
    }
}
自定义拦截器

自定义拦截器,springmvc提供了HandlerInterceptor接口,需要重写preHandle,postHandle,afterCompletion三个方法

public class MyInterceptor implements HandlerInterceptor {
    /**
     * Intercept the execution of a handler. Called after HandlerMapping determined
     * an appropriate handler object, but before HandlerAdapter invokes the handler.
     * <p>DispatcherServlet processes a handler in an execution chain, consisting
     * of any number of interceptors, with the handler itself at the end.
     * With this method, each interceptor can decide to abort the execution chain,
     * typically sending a HTTP error or writing a custom response.
     * <p><strong>Note:</strong> special considerations apply for asynchronous
     * request processing. For more details see
     * {@link AsyncHandlerInterceptor}.
     * <p>The default implementation returns {@code true}.
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  chosen handler to execute, for type and/or instance evaluation
     * @return {@code true} if the execution chain should proceed with the
     * next interceptor or the handler itself. Else, DispatcherServlet assumes
     * that this interceptor has already dealt with the response itself.
     * @throws Exception in case of errors
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle执行了");
        //放行 true表示放行 false表示拦截
        return true;
    }

    /**
     * Intercept the execution of a handler. Called after HandlerAdapter actually
     * invoked the handler, but before the DispatcherServlet renders the view.
     * Can expose additional model objects to the view via the given ModelAndView.
     * <p>DispatcherServlet processes a handler in an execution chain, consisting
     * of any number of interceptors, with the handler itself at the end.
     * With this method, each interceptor can post-process an execution,
     * getting applied in inverse order of the execution chain.
     * <p><strong>Note:</strong> special considerations apply for asynchronous
     * request processing. For more details see
     * {@link AsyncHandlerInterceptor}.
     * <p>The default implementation is empty.
     *
     * @param request      current HTTP request
     * @param response     current HTTP response
     * @param handler      handler (or {@link HandlerMethod}) that started asynchronous
     *                     execution, for type and/or instance examination
     * @param modelAndView the {@code ModelAndView} that the handler returned
     *                     (can also be {@code null})
     * @throws Exception in case of errors
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            //目标方法执行之后,进行增强
        System.out.println("postHandler方法执行了");
    }

    /**
     * Callback after completion of request processing, that is, after rendering
     * the view. Will be called on any outcome of handler execution, thus allows
     * for proper resource cleanup.
     * <p>Note: Will only be called if this interceptor's {@code preHandle}
     * method has successfully completed and returned {@code true}!
     * <p>As with the {@code postHandle} method, the method will be invoked on each
     * interceptor in the chain in reverse order, so the first interceptor will be
     * the last to be invoked.
     * <p><strong>Note:</strong> special considerations apply for asynchronous
     * request processing. For more details see
     * {@link AsyncHandlerInterceptor}.
     * <p>The default implementation is empty.
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  handler (or {@link HandlerMethod}) that started asynchronous
     *                 execution, for type and/or instance examination
     * @param ex       exception thrown on handler execution, if any
     * @throws Exception in case of errors
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion方法执行了");
    }
}

配置拦截器
 <!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--/** 包括路径及其子路径-->
            <!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
            <!--/admin/** 拦截的是/admin/下的所有-->
            <mvc:mapping path="/target"/>
            <!--bean配置的就是拦截器-->
            <bean class="com.lifly.interceptor.MyInterceptor"></bean>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/target"/>
            <bean class="com.lifly.interceptor.MyInterceptor01"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

文件删除与下载

文件上传

文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。

文件上传三要素

表达的提交方式method=“POST”
表单的enctype属性是多部分表单形式enctype=“multipart/form-data”

行动起来

前端页面编写
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传</title>
</head>
<body>
<form action="/upload" enctype="multipart/form-data" method="post">
    用户:<input type="text" name="username"><br>
    请选择要上传的文件:<input type="file" name="file"/><br>
    <input type="submit" value="upload">
</form>
</body>
</html>
文件上传组件配置
 <!--配置文件上传组件-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--设置字符编码-->
        <property name="defaultEncoding" value="UTF-8"/>
        <!--设置上传文件大小-->
        <property name="maxUploadSize" value="10485760"/>
    </bean>
后端代码编写
@Controller
public class UploadController {

    @RequestMapping("/upload")
    public void upload(String username, @RequestParam("file") MultipartFile multipartFile, HttpServletRequest request) throws IOException {
        //获取文件的名称
        String fileName = multipartFile.getOriginalFilename();
        //获取真实路径
        String realPath = request.getServletContext().getRealPath("/upload");
        //将path封装为File对象
        File file = new File(realPath);
        //判断文件是否存在,不存在则创建
        if (!file.exists()){
            file.mkdirs();
        }
        multipartFile.transferTo(new File(file,fileName));
        System.out.println(realPath);
        System.out.println("file upload success");

    }
}

上传文件查找

在这里插入图片描述

文件下载

资源准备

在这里插入图片描述

前端代码编写
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件下载</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/download/?fileName=美女.jpg">美女图一</a>
<a href="${pageContext.request.contextPath}/download/?fileName=5.gif">会动的美女</a>
</body>
</html>
后端代码编写
@Controller
public class DownLoadController {
    @RequestMapping("/download")
    public void download(String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
        //获取服务器文件的真实路径
        String realPath = request.getServletContext().getRealPath("/download");
        //设置响应头
        response.setHeader("Content-Disposition",
                "attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
        File file = new File(realPath, fileName);
        //读取文件--输入流
        InputStream input = new FileInputStream(file);
        //写出文件--输出流
        ServletOutputStream os = response.getOutputStream();

        byte[] bytes = new byte[1024];
        int index = 0;
        //执行写出操作
        while ((index=input.read(bytes)) != -1){
            os.write(bytes,0,index);
            os.flush();
        }
        os.close();
        input.close();
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

double_lifly

点喜欢就是最好的打赏!!

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

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

打赏作者

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

抵扣说明:

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

余额充值