6. 剖析SpringMVC处理Json数据

SpringMVC处理JSON

Gson 谷歌公司的产品

fastJson 阿里的产品

JsonLib

jackson(springmvc默认使用的)

使用jackson需要引三个包:

  • jackson-annotations-2.1.5.jar
  • jackson-core-2.1.5.jar
  • jackson-databind-2.1.5.jar
1. SpringMVC使用

我们先看一下不使用json数据格式查找所有department信息,并返回department_list页面。如果熟悉这个流程可以跳过,还可以跟着再复习一下整个流程特别是xml的配置的具体含义。

1.1 depentment_list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

    <!-- 可选的 Bootstrap 主题文件(一般不用引入) -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
    <table class="table">

        <thead>
        <tr>
            <th>Id</th>
            <th>DepartmentName</th>
        </tr>
        </thead>

        <tbody>
        <c:forEach items="${list}" var="department" varStatus="index">
            <tr>
                <td>${department.id}</td>
                <td>${department.departmentName}</td>
            </tr>
        </c:forEach>
        </tbody>
    </table>
</div>
</body>
</html>
1.2 SpringMVC.xml
<?xml version="1.0" encoding="UTF-8"?>
<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="cn.justweb"/>

    <!--视图解析器-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>

    <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${justweb.driver}"></property>
        <property name="url" value="${justweb.url}"></property>
        <property name="username" value="${justweb.username}"></property>
        <property name="password" value="${justweb.password}"></property>
    </bean>

    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource"></property>
    </bean>


</beans>
1.3 db.properties
justweb.driver=com.mysql.jdbc.Driver
justweb.url=jdbc:mysql://cdb-o6r75r3g.bj.tencentcdb.com:10015/springmvc_day02
justweb.username=root
justweb.password=*******
1.4 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <!--请求方式的过滤器-->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 配置SpringMVC核心控制器:(前端控制器) -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>
1.5 ☆控制层☆

不适用json的情况下

//控制层
@Controller
@RequestMapping("/department")
public class DepartmentController {

    //自动注入
    @Autowired
    DepartmentService service;

    // 如果这里添加了@ResponseBody不会跳转department_list.jsp页面
    @RequestMapping("/findAll")
    public String findAll(Model model){
        //查询所有的部门信息
        List<Department> list = service.findAll();

        //将查询所有的结果封装到request域中
        model.addAttribute( "list",list );
        /**
         * 跳转,这个请求会执行凭借
         * */
        return "department_list";
    }
}

使用@ResponseBody之后我们发现,访问得到的数据是json格式的数据,我们都知道前后端分离开发模式中,后端只需要提供数据接口(这个接口不是单指java里面的interface,而是controller,service,dao)得到json格式的数据,所以没有了跳转到jsp页面的那一步。当然使用了@ResponseBody之后也并不代表着不能进行页面跳转,我们可以使用response.sendRedirect()方法进行跳转。

1.6 service层
@Service
public class EmployeeService {

    @Autowired
    DepartmentDao departmentDao;

    public List<Employee> findAll() {
        //此处查询出来的employee对象里面只存在部门的id.
        List<Employee> list = dao.findAll();

        //遍历list中的employee对象
        for (Employee employee : list) {
            //根据部门id查询出部门对象
            Department department = departmentDao.findById( employee.getId() );
            //重置employee对象中department对象
            employee.setDepartment( department );
        }
        //返回集合
        return  list;
    }
}
1.7 dao层

后面整合MyBatis,暂时使用JdbcTemplate

@Repository
public class DepartmentDao {

    @Autowired
    private JdbcTemplate jt;

    /*查询所有*/
    public List<Department> findAll(){
        List<Department> list = null;
        try {
            list = jt.query( "select * from department", new BeanPropertyRowMapper<>( Department.class ) );
        } catch (DataAccessException e) {
            e.printStackTrace();
        }
        return list;
    }
}
1.8 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    //部门编号
    private Integer id;
    //部门名称
    private String departmentName;

    List<Employee> list;
}
    //
    @ResponseBody
    @RequestMapping("/findAll")
    public List<Department> findAll(HttpServletResponse response) throws Exception{
        //查询所有的部门信息
        List<Department> list = service.findAll();

        System.out.println( "list = " + list );

/**      传统的方法:
        //通过工具类将list转成json字符串
        String s = JsonUtils.objectToJson( list );

        我们学完springMVC之后就可以这样使用:@Responsebody
        需要在springMVC.xml中添加mvc的命名空间和添加注解驱动
         <mvc:annotation-driven/>
 */


        /**
         *  //将查询所有的结果封装到request域中
         * model.addAttribute( "list",list );
         * 跳转,这个请求会执行凭借
         * */
        return list;
2. @RequestBody

@RequestBody 获取一个请求的请求体,也可以接受json格式的数据,并装转成java对象。

在开发中经常使用@RestController代替@Controller,我们为什么使用@RestController呢?请看@RestController的源代码你就会一目了然。

/*
 *
 *Spring 4.0引入了@RestController,这是一个控制器的专用版本,它是一个方便的注释,除了自动添加   	 *@Controller和@ResponseBody注释之外没有其他新魔法。
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

}
    @RequestMapping("/requestBody")
    public String requestBody(@RequestBody String body){
        //不加@RequestBody默认属性匹配
        //@RequestBody可以接收Post请求的所有数据
        System.out.println( "body = " + body );
        //body = username=taoge&desc=lihai,使用form表单post送来的数据,不能使用get请求发送
        //因为@RequestBody是在请求体中拿到数据,而get请求没有请求体
        return "success";
    }
3. @ResponseBody

@ResponseBody:将返回的数据放在响应体中,如果是对象,jackson自动将对象转为json格式,即SpringMVC对JSON的支持。典型spring mvc应用,请求点通常返回html页面。有时我们仅需要实际数据,如使用ajax请求。

使用@ResponseBody之后我们发现,访问得到的数据是json格式的数据,我们都知道前后端分离开发模式中,后端只需要提供数据接口(这个接口不是单指java里面的interface,而是controller,service,dao)得到json格式的数据,所以没有了跳转到jsp页面的那一步。当然使用了@ResponseBody之后也并不代表着不能进行页面跳转,我们可以使用response.sendRedirect()方法进行跳转。

    //查找所有department信息,并返回department_list页面。
    @ResponseBody
    @RequestMapping("/findAll")
    public List<Department> findAll(HttpServletResponse response) throws Exception{
        //查询所有的部门信息
        List<Department> list = service.findAll();

        System.out.println( "list = " + list );

/**      传统的方法:
        //通过工具类将list转成json字符串
        String s = JsonUtils.objectToJson( list );

        我们学完springMVC之后就可以这样使用:@Responsebody
        需要在springMVC.xml中添加mvc的命名空间和添加注解驱动
         <mvc:annotation-driven/>
 */


        /**
         *  //将查询所有的结果封装到request域中
         * model.addAttribute( "list",list );
         * 跳转,这个请求会执行凭借
         * */
        return list;
    }
4. HttpEntity<T>
  • HttpEntity的方式获取请求体
    @RequestMapping("/httpEntity")
    public String httpEntity(HttpEntity<String> httpEntity){
        
        /**httpEntity = <,{host=[localhost:8080], 
         *connection=[keep-alive],
         * upgrade-insecure-requests=[1],
         * user-agent=[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 			 *(KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36], 
         * sec-fetch-mode=[navigate], sec-fetch-user=[?1],
         * accept=		   [text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,;q=0.8,appli		 *cation/signed-exchange;v=b3], sec-fetch-site=[none],
         * accept-encoding=[gzip, deflate, br],
         * accept-language=[zh-CN,zh;q=0.9],
         * cookie=[SL_G_WPT_TO=zh; SL_GWPT_Show_Hide_tmp=undefined; 				  SL_wptGlobTipTmp=undefined;
         * JSESSIONID=EECBD1FAA123518AD4CAA82BEDFCFE97]}
         * */
        System.out.println( "httpEntity = " + httpEntity );

        System.out.println( "httpEntity.getBody() = " + httpEntity.getBody() );

        /**httpEntity.getHeaders().getConnection() = [keep-alive]*/
        System.out.println( "httpEntity.getHeaders().getConnection() = " + 									httpEntity.getHeaders().getConnection() );
        
        return "success";
    }
5. ResponseEntity <T>

将返回的数据放到响应体中,这个响应体使我们可控的。

    @RequestMapping("/download")
    public ResponseEntity<byte[]> download(HttpSession session)throws Exception{

        //1.获取servlet对象
        ServletContext servletContext = session.getServletContext();

        //2.获取目标资源的真实路径
        String realPath = servletContext.getRealPath( "images" );

        //3.创建file对象File.separator根据操作系统自动自适应
        File file = new File( realPath + File.separator + "taoge.png" );

        //4. 创建输入流
        FileInputStream fileInputStream = new FileInputStream( file );

        //5.创建字节数组,将输入流的资源放到字节数组中
        //fileInputStream.availiable 获取里面有多少流
        byte[] bytes = new byte[fileInputStream.available()];

        //6.将输入流放入字节数组中
        fileInputStream.read(bytes);

        //7.封装responseEntity对象
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Content-Disposition","attachment;filename=taotao.png");

        //设置状态码
        HttpStatus status = HttpStatus.OK;

        return new ResponseEntity<>( bytes, httpHeaders, status );;
    }
6. HttpMessageConverter

我们通过上边几个注解的学习,你是否有这样 的疑问–是怎么把对象转成json,又怎么把json数据转成对象的?那么我们就需要了解一下–HttpMessageConverter 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息。

在这里插入图片描述

对上图的解释:

请求报文转成HttpInputMessage输入流,经过HttpMessageConverter转成java对象

java对象经HttpMessageConverter转成输出流HttpOutputMessage,根据输出流生成响应报文。

到这里你可能对HttpMessageConverter产生浓厚的兴趣–你可以根据这篇文章debug去探索一下。HttpMessageConverter是这样转换数据的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值