SpringMVC学习详细笔记

文章目录

  • Spring MVC
    • 1、简介
    • 2、Hello Spring MVC
      • 2.1、项目步骤:
      • 2.2、第一个SpringMVC程序的编写
    • 3、理解SpringMVC的执行原理
      • 3.1、SpringMVC的原理图
      • 3.2、深入理解SpringMVC原理
    • 4、使用注解来实现SpringMVC
    • 5、RequestMapping注解
    • 6、RestFul风格
    • 7、指定访问的方法
    • 8、重定向和转发
    • 9、数据处理
      • 9.1、接受前端数据
      • 9.2、数据显示到前端
    • 10、SpringMVC中的乱码问题
    • 11、JSON技术
      • 11.1、 什么是JSON
      • 11.2、Jackson解析工具
      • 11.2、Fastjson解析工具
    • 12、拦截器
    • 13、文件上传和下载

Spring MVC

1、简介

Spring MVC是Spring Framework的一部分,是基于java实现的MVC的轻量级Web框架。

官网文档地址:https://docs.spring.io/spring-framework/docs/4.2.4.RELEASE/spring-framework-reference/html/mvc.html

Spring MVC的特点:

  • 轻量级,简单易学。
  • 高效,基于请求和响应的MVC框架。
  • 与Spring兼容性较好,无缝结合。
  • 约定优于配置。
  • 功能强大,简洁灵活。

2、Hello Spring MVC

先使用idea编写第一个SpringMVC程序,先感受一先,不需要理解。

2.1、项目步骤:

  1. 创建Maven工程

SpringMVC学习详细笔记_第1张图片

  1. 导入响应的依赖

由于SpringMVC的底层还是servlet,所以还是需要导入servlet和jsp响应的依赖。

<dependencies>
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-webmvcartifactId>
        <version>5.3.8version>
    dependency>
    <dependency>
        <groupId>javax.servletgroupId>
        <artifactId>servlet-apiartifactId>
        <version>2.5version>
    dependency>
    <dependency>
        <groupId>javax.servlet.jspgroupId>
        <artifactId>jsp-apiartifactId>
        <version>2.2version>
    dependency>
    <dependency>
        <groupId>javax.servlet.jsp.jstlgroupId>
        <artifactId>jstlartifactId>
        <version>1.2version>
    dependency>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.12version>
    dependency>
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>8.0.21version>
    dependency>
dependencies>
  1. 加入web框架支持

最总创建的项目为下面这个

SpringMVC学习详细笔记_第2张图片

2.2、第一个SpringMVC程序的编写

步骤:

  1. 配置web.xml文件

<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>springmvcservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:springmvc-servlet.xmlparam-value>
        init-param>
        
        <load-on-startup>1load-on-startup>
    servlet>
    
    <servlet-mapping>
        <servlet-name>springmvcservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>
web-app>
  1. 创建springmvc-servlet.xml的配置文件

  2. 在springmvc-servlet.xml文件中注入映射器

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
  1. 在springvc-servlet.xml文件中注入适配器
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
  1. 在springmvc-servlet.xml文件注入视图解释器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">   
       
    <property name="prefix" value="/WEB-INF/jsp/"/>   
       
    <property name="suffix" value=".jsp"/>
bean>

前缀:访问路劲的前面部分

后缀:访问路径的后面部分

  1. 编写业务逻辑层controller
package com.xiayuan.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloController implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        // 创建ModelAndView对象,用于返回业务的数据
        ModelAndView mv = new ModelAndView();
        // 业务逻辑代码,先不写

        // 把业务获得的数据封装到mv中
        mv.addObject("msg","Hello,SpringMVC!");
        // 把要跳转的视图封装到mv中
        mv.setViewName("hello"); // 在springmvc-servlet.xml中拼接为 /WEB-INF/jsp/hello.jsp
        // 把mv返回给DispatcherServlet
        return mv;
    }
}
  1. 把编写的controller代码注入到spring容器中,编写在springmvc-servlet.xml文件中
<bean id="/hello" class="com.xiayuan.controller.HelloController"/>
  1. 编写测试的页面,在WEB-INF文件夹下创建一个jsp文件夹,在jsp文件夹下创建hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    test


    ${msg}


  1. 把需要的相应的包需要放在lib文件夹中

SpringMVC学习详细笔记_第3张图片

  1. 配置Tomcat启动自己的第一个SpringMVC项目

SpringMVC学习详细笔记_第4张图片

注意:在配置DisapatcherServlet时,拦截的请求是 / 表示拦截所有的请求, /* 也是拦截所有的请求,但是 / 不包括jsp文件,而 /* 会包括jsp文件,所以只能写 / 来拦截所有的请求。

3、理解SpringMVC的执行原理

3.1、SpringMVC的原理图

SpringMVC学习详细笔记_第5张图片

上面就是SpringMVC的原理图,在上面的我们只需要做虚线部分(第七步),而实线部分全是SpringMVC帮我们完成的,只需要配置一下。

3.2、深入理解SpringMVC原理

  1. 中心控制器(DispatcherServlet)

Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。

Spring MVC框架像其他其它MVC框架一样,以请求为驱动,围绕一个中心控制器的servlet派送请求和提供功能,中心控制器实际上就是一个servlet,它是继承至HttpServlet基类。所有的请求给中心控制器来拦截,然后在派送请求。

  1. 分析执行流程
  • DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
  • HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
  • HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器。
  • HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
  • HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
  • Handler让具体的Controller执行。
  • Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
  • HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
  • DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
  • 视图解析器将解析的逻辑视图名传给DispatcherServlet。
  • DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
  • 最终视图响应给用户。

4、使用注解来实现SpringMVC

实现步骤:

  1. 配置web.xml,注册DispatcherServlet

<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>springmvcservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:springmvc-servlet.xmlparam-value>
        init-param>
        <load-on-startup>1load-on-startup>
    servlet>
    <servlet-mapping>
        <servlet-name>springmvcservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>
web-app>

这个配置一般不需要需修改,按照上面的格式书写就行,但是web.xml的版本必须是4.0以上的版本,不然不能运行项目。

  1. 配置springmvc-servlet.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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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">
    
    <context:component-scan base-package="com.xiayuan.controller"/>
    
    <mvc:default-servlet-handler/>
    
    
    <mvc:annotation-driven/>
    
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    bean>
    
beans>

这个配置也是不需要改动的,创建项目后,按照上面的方式书写就行。

  1. 创建controller
package com.xiayuan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller // 使用注解来完成装配Controller,表示会被spring接管
@RequestMapping("/hello") // 用于设置请求的url,可以不写,写的话就是下面路劲的父路径
public class HelloController {

    // 一个普通的方法,这个方法必须返回一个字符串
    @RequestMapping("/h1") // 用于请求的路径,现在的请求路径为 localhost:端口号/项目名/hello/h1
    public String hello(Model model){
        // 通过参数model来封装数据
        model.addAttribute("msg","Hello,SpringMVCAnnotation!"); // 封装数据
        return "hello"; // 这个字符串就是就是视图的名字,会被视图解析器处理
    }
}
  1. 总结步骤
  • 新建项目
  • 导入需要的包
  • 配置web.xml文件,一般不需要改动
  • 配置springmvc-servlet.xml文件,一般也不需要改动
  • 创建controller类,控制类,设置访问路径、封装数据、返回视图的名称。
  • 创建一个视图,与controller对应。
  • 调试Tomcat运行程序。

5、RequestMapping注解

注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

@Controller
@RequestMapping("/test")
public class HelloController {
    @RequestMapping("/hello")
    public String sayHello(Model model){
        model.addAttribute("msg","Hello,SpringMVCAnnotation!");
        return "hello";
    }
}

现在上面的控制器的访问路径就为:localhost:端口号/项目名/test/hello

6、RestFul风格

Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

传统的get传参方法:

localhost:/test/hello?name=张三

RestFul风格的传参方式:

localhost:test/hello/张三

上面的张三就是一个参数。

优点:

  • 使url看起来更加简洁
  • 更加安全

实现RestFul风格的步骤:

  1. 创建一个测试的控制器
package com.xiayuan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RestFulController {
    @RequestMapping("/hello")
    public String test(Model model){
        model.addAttribute("msg","Hello,RestFul!");
        return "hello";
    }
}
  1. 设置参数
public String test(@PathVariable String a, @PathVariable String b, Model model){
    model.addAttribute("msg","Hello,RestFul!");
    return "hello";
}

需要使用@PathVariable注解来注解参数,上面a和b就是参数的名称。

  1. 把参数绑定到url模板上
@Controller
public class RestFulController {
    @RequestMapping("/hello/{a}/{b}")
    public String test(@PathVariable String a, @PathVariable String b, Model model){
        model.addAttribute("msg","Hello,RestFul!");
        return "hello";
    }
}

现在的路径就为 localhost:/项目名/hello/参数a/参数b

SpringMVC学习详细笔记_第6张图片

7、指定访问的方法

一般url默认的访问方法就是GET方法,但是实际有时候需要其它的访问方法。我们可以指定访问的方法。

指定方式一:

@Controller
public class RestFulController {
    @RequestMapping(value = "/hello/{a}/{b}",method = RequestMethod.POST)
    public String test(@PathVariable String a, @PathVariable String b, Model model){
        model.addAttribute("msg","Hello,RestFul!");
        System.out.println(a+b);
        return "hello";
    }
}

在@RequestMapping注解中指定访问的方法。

注意:必须以键值对的形式存在,必须写value也可以是path,method的值是一个枚举类型的变量。

指定方式二:

@PostMapping("/hello/{a}/{b}")
public String test1(@PathVariable String a, @PathVariable String b, Model model){
    model.addAttribute("msg","Hello,RestFul!");
    System.out.println(a+b);
    return "hello";
}

通过使用对应方式的注解也可以指定访问的方法,相当于把@RequestMapping注解分开书写。

其它的几种访问方法的注解:

  • POST方法:@PostMapping
  • GET方法:@GETMapping
  • DELETD方法:@DeleteMapping
  • PUT方法:@PutMapping
  • PATCH方法:@PatchMapping(该方法是PUT方法的补充,用于局部更新)

8、重定向和转发

原始的重定向和请求转发:

@Controller
public class TestController {
    @RequestMapping("/hello")
    public String test1(HttpServletRequest request, HttpServletResponse response,Model model){
        request.getSession();
        return "hello";
    }
}

在控制器的方法上可以增加HttpServletRequest和HttpServletResponse两个参数,这两个参数就是servlet中请求和响应的两个参数,它们在servlet中所有的操作都是可以在springmvc中完成的。

springmvc中的重定向和请求转发:

注意:使用springmvc中的重定向和请求转发,需要去掉视图解析器,它们是不会经过视图解析器的,如果存在视图解析器,会把视图拼接导致找不到资源。

@RequestMapping("/t2")
public String test2(HttpServletRequest request, HttpServletResponse response,Model model){
    // return "redirect:/login.jsp" 重定向
    return "forward:/login.jsp"; // 请求转发
}

:注意重定向不能重定向到WEB-INF下的资源,请求转发也可以省略不写forward:

9、数据处理

9.1、接受前端数据

  1. 接受一个普通的数据:通过url中的参数来获得前端参数。
@RequestMapping("/t1")
public String test1(@RequestParam("name") String name, @RequestParam("password") String password, Model model){
    // @RequestParam注解中的name和password就是从前端传过来的参数名称
    // 必须和前端参数名称一样,后面的string的名称可以和前端参数名称不一样
    System.out.println("name = "+name);
    System.out.println("password = "+password);
    return "test";
}
  1. 接受一个对象的参数:通过封装一个实体类来接受数据。

首先写一个user类

package com.xiayuan.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private String password;
}
@RequestMapping("/t2")
public String test2(User user,Model model){
    System.out.println(user);
    return "test";
}

注意:把user作为参数来接受前端数据,而且前端的参数名称必须要和接受对象的字段名称保持一致,不能不一样。

上面的传参的访问地址就为:localhost:端口名/项目名/t2?name=zhansan&password=123

SpringMVC学习详细笔记_第7张图片

注意:如果字段不一样的字段,就会自动为默认值。

9.2、数据显示到前端

一共有三种方式,ModelAndView、ModelMap、Model

ModelAndView:

@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
    ModelAndView mv = new ModelAndView();
    mv.addObject("msg","疯转的数据!");
    mv.setViewName("hello");
    return mv;
}

这是之前的数据封装方式,使用的就是ModelAndView来给前端显示数据的。

ModelMap:

@RequestMapping("/t3")
public String test3(ModelMap modelMap){
    modelMap.addAttribute("msg","封装的数据!");
    return "test";
}

Model:

@RequestMapping("/t4")
public String test4(Model model){
    model.addAttribute("msg","封装的数据!");
    return "test";
}

注意:ModelMap它继承了LinkedHashMap,所有他有该类的所有操作,而Model是ModelMap的简洁版本,没有继承LinkedHashMap

​ Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解; ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性; ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。

我们一般使用Model来封装数据。

10、SpringMVC中的乱码问题

在前端传入的参数中有中文字符,在后端就会存在乱码问题。我们通常使用过滤器去解决乱码问题。

方式一:使用SpringMVC给我们提供的过滤器来解决乱码问题。

<filter>
    <filter-name>encodingfilter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
    <init-param>
        <param-name>encodingparam-name>
        <param-value>utf-8param-value>
    init-param>
filter>
<filter-mapping>
    <filter-name>encodingfilter-name>
    <url-pattern>/*url-pattern>
filter-mapping>

我们只需要在web.xml中注册一个springmvc帮我们写好的乱码处理过滤器就可以了。

如果还是不能够解决乱码问题,使用下面的终极乱码解决方案。

方式二:

自己定义一个filter

<filter>
    <filter-name>GenericEncodingFilterfilter-name>
    <filter-class>com.xiayuan.filter.GenericEncodingFilterfilter-class>
filter>
<filter-mapping>
    <filter-name>GenericEncodingFilterfilter-name>
    <url-pattern>/*url-pattern>
filter-mapping>

filter代码:

package com.xiayuan.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 解决get和post请求 全部乱码的过滤器
 */
public class GenericEncodingFilter implements Filter {
    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //处理response的字符编码
        HttpServletResponse myResponse = (HttpServletResponse) response;
        myResponse.setContentType("text/html;charset=UTF-8");
        // 转型为与协议相关对象
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        // 对request包装增强
        HttpServletRequest myrequest = new MyRequest(httpServletRequest);
        chain.doFilter(myrequest, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
}

还需在同一个包下创建一个增强的类

package com.xiayuan.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.UnsupportedEncodingException;
import java.util.Map;


//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
    private HttpServletRequest request;
    //是否编码的标记
    private boolean hasEncode;
    // 定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
    public MyRequest(HttpServletRequest request) {
        super(request);// super必须写
         this.request = request;
    }
    // 对需要增强方法 进行覆盖
    @Override
    public Map getParameterMap() {
        // 先获得请求方式
        String method = request.getMethod();
        if (method.equalsIgnoreCase("post")) {
            // post请求
            try {
                // 处理post乱码
                request.setCharacterEncoding("utf-8");
                return request.getParameterMap();
             } catch (UnsupportedEncodingException e) {
                 e.printStackTrace();
            }
         } else if (method.equalsIgnoreCase("get")) {
                // get请求
                Map<String, String[]> parameterMap = request.getParameterMap();
                if (!hasEncode) { // 确保get手动编码逻辑只运行一次
                for (String parameterName : parameterMap.keySet()) {
                    String[] values = parameterMap.get(parameterName);
                    if (values != null) {
                        for (int i = 0; i < values.length; i++) {
                            try {
                                    // 处理get乱码
                                    values[i] = new String(values[i].getBytes("ISO-8859-1"), "utf-8");
                             } catch (UnsupportedEncodingException e) {
                                 e.printStackTrace();
                            }
                        }
                    }
                }
                hasEncode = true;
                }
                return parameterMap;
        }
        return super.getParameterMap();
    }
    //取一个值
    @Override
    public String getParameter(String name) {
        Map<String, String[]> parameterMap = getParameterMap();
        String[] values = parameterMap.get(name);
        if (values == null) {
            return null;
        }
        return values[0];
        // 取回参数的第一个值
    }
    // 取所有值
    @Override
    public String[] getParameterValues(String name) {
        Map<String, String[]> parameterMap = getParameterMap();
        String[] values = parameterMap.get(name);
        return values;
    }
}

springmvc给我们提供的过滤器可以解决大部分的乱码问题,我们通常使用springmvc提供的filter,实在不能解决的乱码问题在使用第二种方式。

11、JSON技术

11.1、 什么是JSON

  • JSON(js对象标记)是一种轻量级的数据交换格式,用于实现前后端分离,目前使用广泛。
  • 它的形式简洁和清晰。
  • 在js中任何类型都可以通过JSON来表示。

js中的对象:

var obj = {
    name:"张三",
    age:18,
    sex:"男"
}
  • 对象以键值对表示,使用逗号隔开。
  • 大括号来保存对象。
  • [] 用来表示数组。

JSON的语法:

JSON也是用键值对来保存js中对象的字符串的表示方式,本质上就是一个字符串。

 var json = '{"name":"张三","age":18},"sex":"男"}';

js中JSON与对象的相互转换:

  1. 对象转换成JSON:
var obj = {
    name:"张三",
    age:18,
    sex:"男"
}
var json = JSON.stringify(obj);
console.log(json);

上面就是把obj这个对象转换成json字符串。

  1. JSON转换成对象:
var json = JSON.stringify(obj);
obj = JSON.parse(json);
console.log(typeof obj);

上面就是把json字符串转换成js对象。

11.2、Jackson解析工具

Jackson解析工具是把java的对象解析为一个前端能够识别的json字符串。下面介绍它的使用步骤。

  1. 导入Jackson的依赖
<dependency>
    <groupId>com.fasterxml.jackson.coregroupId>
    <artifactId>jackson-databindartifactId>
    <version>2.12.5version>
dependency>
  1. 创建一个user对象
package com.xiayuan.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
    private String sex;
}
  1. 配置springmvc的环境,创建一个UserController控制器。
  2. Jackson的使用方式

方式一:

@Controller
public class UserController {
    @RequestMapping("/json1")
    @ResponseBody // 这个注解使该方法返回一个字符串,不会经过视图解析器。
    public String test1() throws JsonProcessingException {
        User user = new User("张三", 18);
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(user);
    }
}

@Controller和@ResponseBody注解联合使用。

方式二:

@RestController
public class UserController {

    @RequestMapping("/json2")
    public String test2() throws JsonProcessingException {
        User user = new User("张三",19);
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(user);
    }
}

@RestController注解使类中的所有的方法都返回一个字符串,不会经过视图解析器。

解决JSON乱码问题:


<mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg value="UTF-8"/>
        bean>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="failOnEmptyBeans" value="false"/>
                bean>
            property>
        bean>
    mvc:message-converters>
mvc:annotation-driven>

在springmvc-servlet.xml文件中配置JSON乱码问题的解决方案。

编写JSON转换的工具类:

package com.xiayuan.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.text.SimpleDateFormat;

public class JsonUtil {

    // 把指定的对象转换为JSON字符换
    public static String getJson(Object object){
        // 如果不是转换一个日期格式,它会自动传入一个默认的日期的格式
        return getJson(object,"yyyy-MM-dd HH:mm:ss");
    }

    // 把日期按照指定的格式转换成JSON字符串
    public static String getJson(Object object,String format) {
        ObjectMapper mapper = new ObjectMapper();
        // 设置不适用时间差的方式
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        mapper.setDateFormat(sdf);
        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

11.2、Fastjson解析工具

在上面的环境下进行测试。

首先导入Fastjson依赖。

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>fastjsonartifactId>
    <version>1.2.75version>
dependency>

使用方法:

  1. 将Java对象转换成JSON字符串
String str1 = JSON.toJSONString(object);
  1. 将JSON字符串转换成Java对象
Object object = JSON.parseObject(json,Object.class);
  1. 将Java对象转换成JSON对象
JSONObject jsonObject = (JSONObject) JSON.toJSON(javaObject);
  1. 将JSON对象转换成Java对象
Object javaObject = JSON.toJavaObject(jsonObject, Object.class);

JSON对象:

  • JSONObject实现了Map接口, 猜想 JSONObject底层操作是由Map实现的。
  • JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取”键:值”对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。

12、拦截器

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

springMVC中的拦截器是基于AOP思想来实现的,只有springMVC框架才能使用该拦截器。

实现步骤:

  1. 编写一个拦截器类,MyInterceptor,并实现HandlerInterceptor接口,覆写接口中的方法
package com.xiayuan.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
  • preHandle方法:是过滤请求,相当于servlet中的doFilter,如果返回true就放行该请求,返回false就不会放行请求。
  • postHandle方法:是请求的返回的过滤,一般用于写日志。
  • afterCompletion方法:是来清理过滤器的,最后执行,也是用于日志的。
  1. 配置拦截器,配置到spring容器中
<mvc:interceptors>
    <mvc:interceptor>
        
        
        
        <mvc:mapping path="/admin/**"/> 
        
        <bean class="com.xiayuan.interceptor.MyInterceptor"/>
    mvc:interceptor>
mvc:interceptors>

拦截器一般应用与拦截未登录的用户和非法访问的用户。

13、文件上传和下载

文件上传:
在springmvc中一共有两种方式实现文件上传。

方式一:

  1. 导入相应的依赖:
<dependency>
    <groupId>commons-fileuploadgroupId>
    <artifactId>commons-fileuploadartifactId>
    <version>1.3.3version>
dependency>
<dependency>
    <groupId>javax.servletgroupId>
    <artifactId>javax.servlet-apiartifactId>
    <version>4.0.1version>
dependency>

注意:servlet-api的版本必须是高版本的,不然不会支持相应的功能。

  1. 配置web环境
  2. 需要在spring容器中配置一个multipartResolver的bean

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    
    
    <property name="defaultEncoding" value="utf-8"/>    
    
    <property name="maxUploadSize" value="10485760"/>
    <property name="maxInMemorySize" value="40960"/>
bean>

注意:bean的id属性的名称必须是multipartResolver,不然会出错。

  1. 编写文件上传的表单
  1. 编写文件上传的controller处理方法
public String upload(@RequestParam("my_file") CommonsMultipartFile file , HttpServletRequest request) throws IOException{
    //获取文件名 : file.getOriginalFilename();
    String uploadFileName = file.getOriginalFilename();
    // 如果文件名为空,直接回到首页!
    if ("".equals(uploadFileName)){
        return "redirect:/index.jsp";
     }
    System.out.println("上传文件名 : "+uploadFileName);
    // 上传路径保存设置
    String path = request.getServletContext().getRealPath("/upload");
    // 如果路径不存在,创建一个        
    File realPath = new File(path);
    if (!realPath.exists()){
        realPath.mkdir();
    }
    System.out.println("上传文件保存地址:"+realPath);
    InputStream is = file.getInputStream(); //文件输入流
    OutputStream os = new FileOutputStream(new File(realPath,uploadFileName));
    // 文件输出流
    // 读取写出
    int len=0;
    byte[] buffer = new byte[1024];
    while ((len=is.read(buffer))!=-1){
        os.write(buffer,0,len);
        os.flush();
    }
    os.close();
    is.close();
    return "redirect:/index.jsp";
}

上面的代码在写文件上传的时候几乎是不需要修改的,只需要修改上传的保存路径和前端传过来的参数名称。

方式二:

在上面的环境基础之上,修改文件上传的controller控制器就可以了

修改后的controller

/* * 采用file.Transto 来保存上传的文件 */
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("my_file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
    //上传路径保存设置
    String path = request.getServletContext().getRealPath("/upload");
    File realPath = new File(path);
    if (!realPath.exists()){
        realPath.mkdir();
    }
    // 上传文件地址
    System.out.println("上传文件保存地址:"+realPath);
    // 通过CommonsMultipartFile的方法直接写文件(注意这个时候)
    file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
    return "redirect:/index.jsp";}
}

建议使用第二种方式,比较简单。我们还可以使用UUID来防止文件上传时重名的问题。

文件下载:

文件下载也有两种方式,第一种就是通过超链接来下载文件,但是存在一个弊端。

超链接下载文件对于浏览器能够解析的资源就直接在页面给你展示,浏览器不能够解析的资源会让你下载。

<a href="${pageContext.request.contextPath}/upload/lab.png">通过超链接下载a>

还有一种方式,就是通过springmvc来实现文件的下载:

在上述的环境下,只需编写一个文件下载的controller来实现

@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception {
    //要下载的图片地址
    String  path = request.getServletContext().getRealPath("/upload");
    String  fileName = "lab.png";
    // 1、设置response 响应头
    response.reset();
    // 设置页面不缓存,清空buffer
    response.setCharacterEncoding("UTF-8");
    // 字符编码
    response.setContentType("multipart/form-data");
    // 二进制传输数据
    // 设置响应头
    response.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
    File file = new File(path,fileName);
    // 2、 读取文件--输入流
    InputStream input=new FileInputStream(file);
    // 3、 写出文件--输出流
    OutputStream out = response.getOutputStream();
    byte[] buff =new byte[1024];
    int index=0;
    // 4、执行 写出操作
    while((index= input.read(buff))!= -1){
        out.write(buff, 0, index);
        out.flush();
    }
    out.close();
    input.close();
    return null;
}

这个controller也是不需要修改的,只需要修改下载的路径和文件名称。前端只需使用 a 标签来请求后台的controller就可以了。

你可能感兴趣的:(Java,Web,mvc,spring,java,springmvc)