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/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

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

    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/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是這樣轉換數據的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章