Java学习笔记13-1——SpringMVC
文章目錄
- 1.什么是MVC
- 回顧Servlet
- 2.什么是SpringMVC
- 概述
- 中心控制器
- SpringMVC執(zhí)行原理
- 3.第一個(gè)SpringMVC 程序
- 使用XML配置實(shí)現(xiàn)
- 使用注解實(shí)現(xiàn)
- 4.控制器和RestFul風(fēng)格
- 控制器Controller
- 實(shí)現(xiàn)Controller接口
- 使用注解@Controller
- RequestMapping
- RestFul 風(fēng)格
- 擴(kuò)展:小黃鴨調(diào)試法
- 5.結(jié)果跳轉(zhuǎn)方式
- ModelAndView
- ServletAPI
- SpringMVC
- 6.數(shù)據(jù)處理
- 處理提交數(shù)據(jù)
- 參數(shù)名一致
- 參數(shù)名不一致
- 提交的是一個(gè)對(duì)象
- 數(shù)據(jù)顯示到前端
- 第一種 : 通過(guò)ModelAndView
- 第二種 : 通過(guò)ModelMap
- 第三種 : 通過(guò)Model
- 對(duì)比
- 7.亂碼問(wèn)題
- 8.JSON交互處理
- 什么是JSON?
- JSON解析工具Jackson的使用
- JSON亂碼問(wèn)題
- 輸出JSON集合
- 輸出時(shí)間對(duì)象
- 抽取為工具類
- JSON解析工具FastJson的使用
- 9.AJAX
- 簡(jiǎn)介
- 偽造Ajax
- jQuery.ajax
- 10.攔截器
- 11.文件上傳和下載
1.什么是MVC
- MVC是模型(Model)、視圖(View)、控制器(Controller)的簡(jiǎn)寫,是一種軟件設(shè)計(jì)規(guī)范。是將業(yè)務(wù)邏輯、數(shù)據(jù)、顯示分離的方法來(lái)組織代碼。
- MVC主要作用是降低了視圖與業(yè)務(wù)邏輯間的雙向偶合。
- MVC不是一種設(shè)計(jì)模式,MVC是一種架構(gòu)模式。當(dāng)然不同的MVC存在差異。
Model(模型):數(shù)據(jù)模型,提供要展示的數(shù)據(jù),因此包含數(shù)據(jù)和行為,可以認(rèn)為是領(lǐng)域模型或JavaBean組件(包含數(shù)據(jù)和行為),不過(guò)現(xiàn)在一般都分離開(kāi)來(lái):Value Object(數(shù)據(jù)Dao) 和 服務(wù)層(行為Service)。也就是模型提供了模型數(shù)據(jù)查詢和模型數(shù)據(jù)的狀態(tài)更新等功能,包括數(shù)據(jù)和業(yè)務(wù)。
View(視圖):負(fù)責(zé)進(jìn)行模型的展示,一般就是我們見(jiàn)到的用戶界面,客戶想看到的東西。
Controller(控制器):接收用戶請(qǐng)求,委托給模型進(jìn)行處理(狀態(tài)改變),處理完畢后把返回的模型數(shù)據(jù)返回給視圖,由視圖負(fù)責(zé)展示。也就是說(shuō)控制器做了個(gè)調(diào)度員的工作。
最典型的MVC就是JSP + Servlet + Java Bean的模式
職責(zé)分析:
Controller:控制器
- 取得表單數(shù)據(jù)
- 調(diào)用業(yè)務(wù)邏輯
- 轉(zhuǎn)向指定的頁(yè)面
Model:模型
- 業(yè)務(wù)邏輯
- 保存數(shù)據(jù)的狀態(tài)
View:視圖
- 顯示頁(yè)面
回顧Servlet
1、新建一個(gè)Maven工程當(dāng)做父工程,導(dǎo)入依賴
<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.9.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency> </dependencies>2、編寫一個(gè)Servlet類,用來(lái)處理用戶的請(qǐng)求
//實(shí)現(xiàn)Servlet接口 public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//取得參數(shù)String method = req.getParameter("method");if (method.equals("add")){req.getSession().setAttribute("msg","執(zhí)行了add方法");}if (method.equals("delete")){req.getSession().setAttribute("msg","執(zhí)行了delete方法");}//業(yè)務(wù)邏輯//視圖跳轉(zhuǎn)req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req,resp);} }3、編寫Hello.jsp,在WEB-INF目錄下新建一個(gè)jsp的文件夾,新建hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body>${msg} </body> </html>4、在web.xml中注冊(cè)Servlet
<?xml version="1.0" encoding="UTF-8"?> <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>HelloServlet</servlet-name><servlet-class>HelloServlet</servlet-class></servlet><servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello</url-pattern></servlet-mapping> </web-app>5、配置Tomcat,并啟動(dòng)測(cè)試
localhost:8080/user?method=add
localhost:8080/user?method=delete
MVC框架要做哪些事情
- 將url映射到j(luò)ava類或java類的方法
- 封裝用戶提交的數(shù)據(jù)
- 處理請(qǐng)求–調(diào)用相關(guān)的業(yè)務(wù)處理–封裝響應(yīng)數(shù)據(jù)
- 將響應(yīng)的數(shù)據(jù)進(jìn)行渲染 . jsp / html 等表示層數(shù)據(jù)
說(shuō)明:
? 常見(jiàn)的服務(wù)器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常見(jiàn)前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另外一些模式如:MVP、MVVM 等等…
2.什么是SpringMVC
概述
Spring MVC是Spring Framework的一部分,是基于Java實(shí)現(xiàn)MVC的輕量級(jí)Web框架。
查看官方文檔:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web
我們?yōu)槭裁匆獙W(xué)習(xí)SpringMVC呢?
Spring MVC的特點(diǎn):
- 輕量級(jí),簡(jiǎn)單易學(xué)
- 高效 , 基于請(qǐng)求響應(yīng)的MVC框架
- 與Spring兼容性好,無(wú)縫結(jié)合
- 約定優(yōu)于配置
- 功能強(qiáng)大:RESTful、數(shù)據(jù)驗(yàn)證、格式化、本地化、主題等
- 簡(jiǎn)潔靈活
Spring的web框架圍繞DispatcherServlet [ 調(diào)度Servlet ] 設(shè)計(jì)。
DispatcherServlet的作用是將請(qǐng)求分發(fā)到不同的處理器。從Spring 2.5開(kāi)始,使用Java 5或者以上版本的用戶可以采用基于注解形式進(jìn)行開(kāi)發(fā),十分簡(jiǎn)潔;
正因?yàn)镾pringMVC好,簡(jiǎn)單,便捷,易學(xué),天生和Spring無(wú)縫集成(使用SpringIoC和AOP),使用約定優(yōu)于配置。能夠進(jìn)行簡(jiǎn)單的junit測(cè)試。支持Restful風(fēng)格。異常處理,本地化,國(guó)際化,數(shù)據(jù)驗(yàn)證,類型轉(zhuǎn)換,攔截器等等,所以我們要學(xué)習(xí)。
最重要的一點(diǎn)還是用的人多,使用的公司多。
中心控制器
Spring的web框架圍繞DispatcherServlet設(shè)計(jì)。DispatcherServlet的作用是將請(qǐng)求分發(fā)到不同的處理器。
DispatcherServlet一級(jí)一級(jí)繼承,最終繼承的是Servlet,所以DispatcherServlet本質(zhì)也是在處理一些響應(yīng)和請(qǐng)求。如下圖所示,這樣多加一層的架構(gòu)好處是不用針對(duì)單個(gè)Servlet一個(gè)個(gè)去配置,現(xiàn)在可以統(tǒng)一配置并順帶管理。
Spring MVC框架像許多其他MVC框架一樣, 以請(qǐng)求為驅(qū)動(dòng) , 圍繞一個(gè)中心Servlet分派請(qǐng)求及提供其他功能,DispatcherServlet是一個(gè)實(shí)際的Servlet (它繼承自HttpServlet 基類)。
SpringMVC的原理如下圖所示:
當(dāng)發(fā)起請(qǐng)求時(shí)被前置的控制器攔截到請(qǐng)求,根據(jù)請(qǐng)求參數(shù)生成代理請(qǐng)求,找到請(qǐng)求對(duì)應(yīng)的實(shí)際控制器,控制器處理請(qǐng)求,創(chuàng)建數(shù)據(jù)模型,訪問(wèn)數(shù)據(jù)庫(kù),將模型響應(yīng)給中心控制器,控制器使用模型與視圖渲染視圖結(jié)果,將結(jié)果返回給中心控制器,再將結(jié)果返回給請(qǐng)求者。
SpringMVC執(zhí)行原理
圖為SpringMVC的一個(gè)較完整的流程圖,實(shí)線表示SpringMVC框架提供的技術(shù),不需要開(kāi)發(fā)者實(shí)現(xiàn),虛線表示需要開(kāi)發(fā)者實(shí)現(xiàn)。
簡(jiǎn)要分析執(zhí)行流程
1、DispatcherServlet表示前置控制器,是整個(gè)SpringMVC的控制中心。用戶發(fā)出請(qǐng)求,
- DispatcherServlet接收請(qǐng)求并攔截請(qǐng)求。
- 我們假設(shè)請(qǐng)求的url為 : http://localhost:8080/SpringMVC/hello
- 如上url拆分成三部分:
- http://localhost:8080 ------> 服務(wù)器域名
- SpringMVC ------> 部署在服務(wù)器上的web站點(diǎn)
- hello ------> 表示控制器
- 通過(guò)分析,如上url表示為:請(qǐng)求位于服務(wù)器localhost:8080上的SpringMVC站點(diǎn)的hello控制器。
2、HandlerMapping為處理器映射。DispatcherServlet調(diào)用HandlerMapping,HandlerMapping根據(jù)請(qǐng)求url查找Handler。
3、HandlerExecution表示具體的Handler,其主要作用是根據(jù)url查找控制器,如上url被查找控制器為:hello。
4、HandlerExecution將解析后的信息傳遞給DispatcherServlet,如解析控制器映射等。
5、HandlerAdapter表示處理器適配器,其按照特定的規(guī)則去執(zhí)行Handler。
6、Handler讓具體的Controller執(zhí)行。
7、Controller將具體的執(zhí)行信息返回給HandlerAdapter,如ModelAndView。
8、HandlerAdapter將視圖邏輯名或模型傳遞給DispatcherServlet。
9、DispatcherServlet調(diào)用視圖解析器(ViewResolver)來(lái)解析HandlerAdapter傳遞的邏輯視圖名。
10、視圖解析器將解析的邏輯視圖名傳給DispatcherServlet。
11、DispatcherServlet根據(jù)視圖解析器解析的視圖結(jié)果,調(diào)用具體的視圖。
12、最終視圖呈現(xiàn)給用戶。
3.第一個(gè)SpringMVC 程序
使用XML配置實(shí)現(xiàn)
1、新建一個(gè)子Moudle,springmvc-02-hello,添加web的支持
2、確定導(dǎo)入了SpringMVC 的依賴
3、配置web.xml,注冊(cè)DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?> <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"><!--注冊(cè)DispatcherServlet--><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--關(guān)聯(lián)一個(gè)springmvc的配置文件:【servlet-name】-servlet.xml--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!--啟動(dòng)級(jí)別-1--><load-on-startup>1</load-on-startup></servlet><!-- / 為匹配所有的請(qǐng)求(不包括.jsp)--><!-- /* 為匹配所有的請(qǐng)求(包括.jsp)--><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>4、編寫SpringMVC 的 配置文件!名稱:springmvc-servlet.xml : [servletname]-servlet.xml
說(shuō)明,這里的名稱要求是按照官方來(lái)的
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--添加處理映射器--><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/><!--添加處理器適配器--><bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/><!--視圖解析器:DispatcherServlet給他的ModelAndView--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"><!--前綴--><property name="prefix" value="/WEB-INF/jsp/"/><!--后綴--><property name="suffix" value=".jsp"/></bean><!--對(duì)寫好的類注冊(cè)bean--><bean id="/hello" class="com.cheng.controller.HelloController"/></beans>5、編寫我們要操作業(yè)務(wù)Controller,要么實(shí)現(xiàn)Controller接口,要么增加注解;需要返回一個(gè)ModelAndView,裝數(shù)據(jù),封視圖
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;//注意:這里我們先導(dǎo)入Controller接口 public class HelloController implements Controller {public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {//ModelAndView 模型和視圖ModelAndView mv = new ModelAndView();//封裝對(duì)象,放在ModelAndView中。Modelmv.addObject("msg","HelloSpringMVC!");//封裝要跳轉(zhuǎn)的視圖,放在ModelAndView中mv.setViewName("hello"); // 最終會(huì)被拼接成/WEB-INF/jsp/hello.jspreturn mv;} }6、將自己的類交給SpringIOC容器,注冊(cè)bean
<!--對(duì)寫好的類注冊(cè)bean--><bean id="/hello" class="com.cheng.controller.HelloController"/>7、寫要跳轉(zhuǎn)的jsp頁(yè)面,顯示ModelandView存放的數(shù)據(jù),以及我們的正常頁(yè)面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>hello</title> </head> <body> ${msg} </body> </html>8、配置Tomcat,啟動(dòng)測(cè)試
可能遇到的問(wèn)題:訪問(wèn)出現(xiàn)404,排查步驟:
-
查看控制臺(tái)輸出,看一下是不是缺少了什么jar包。
-
如果jar包存在,顯示無(wú)法輸出,就在IDEA的項(xiàng)目發(fā)布中,添加lib依賴!
-
重啟Tomcat 即可解決
我們來(lái)看個(gè)注解版實(shí)現(xiàn),這才是SpringMVC的精髓。
使用注解實(shí)現(xiàn)
1、新建一個(gè)Moudle,springmvc-03-annotation 。添加web支持
2、由于Maven可能存在資源過(guò)濾的問(wèn)題,我們將配置完善
<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources> </build>3、在pom.xml文件引入相關(guān)的依賴:主要有Spring框架核心庫(kù)、Spring MVC、servlet , JSTL等。我們?cè)诟敢蕾囍幸呀?jīng)引入了!
4、配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <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"><!--注冊(cè)servlet--><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--初始化Spring配置文件的位置--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!--啟動(dòng)順序,數(shù)字越小,啟動(dòng)越早--><load-on-startup>1</load-on-startup></servlet><!--所有的請(qǐng)求都會(huì)被SpringMVC攔截--><servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping> </web-app> <!--這是使用注解開(kāi)發(fā)時(shí)固定的配置-->注意 / 和 /* 的區(qū)別:
< url-pattern > / </ url-pattern > 不會(huì)匹配到.jsp, 只針對(duì)我們編寫的請(qǐng)求;即:.jsp 不會(huì)進(jìn)入spring的 DispatcherServlet類 。
< url-pattern > /* </ url-pattern > 會(huì)匹配 *.jsp,會(huì)出現(xiàn)返回 jsp視圖 時(shí)再次進(jìn)入spring的DispatcherServlet 類,導(dǎo)致找不到對(duì)應(yīng)的controller所以報(bào)404錯(cuò)。
- 注意web.xml版本問(wèn)題,要最新版!4.0
- 注冊(cè)DispatcherServlet
- 關(guān)聯(lián)SpringMVC的配置文件
- 啟動(dòng)級(jí)別為1
- 映射路徑為 / 【不要用/*,會(huì)404】
5、添加SpringMVC配置文件
在resource目錄下添加springmvc-servlet.xml配置文件,配置的形式與Spring容器配置基本類似,為了支持基于注解的IOC,設(shè)置了自動(dòng)掃描包的功能,具體配置信息如下:
<?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"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自動(dòng)掃描包,讓指定包下的注解生效,由IOC容器統(tǒng)一管理 --><context:component-scan base-package="com.cheng.controller"/><!-- 讓Spring MVC不處理靜態(tài)資源 --><mvc:default-servlet-handler /><!--支持mvc注解驅(qū)動(dòng)在spring中一般采用@RequestMapping注解來(lái)完成映射關(guān)系要想使@RequestMapping注解生效必須向上下文中注冊(cè)DefaultAnnotationHandlerMapping和一個(gè)AnnotationMethodHandlerAdapter實(shí)例這兩個(gè)實(shí)例分別在類級(jí)別和方法級(jí)別處理。而annotation-driven配置幫助我們自動(dòng)完成上述兩個(gè)實(shí)例的注入。--><mvc:annotation-driven /><!-- 視圖解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!-- 前綴 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后綴 --><property name="suffix" value=".jsp" /></bean></beans> <!--這也是固定配置,需要修改的只有需要注入IOC的包-->在視圖解析器中我們把所有的視圖都存放在/WEB-INF/目錄下,這樣可以保證視圖安全,因?yàn)檫@個(gè)目錄下的文件,客戶端不能直接訪問(wèn)。
- 讓IOC的注解生效
- 靜態(tài)資源過(guò)濾 :HTML . JS . CSS . 圖片 , 視頻 …
- MVC的注解驅(qū)動(dòng)
- 配置視圖解析器
6、創(chuàng)建Controller
編寫一個(gè)Java控制類
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping;@Controller @RequestMapping("/h1") public class HelloController {//類上注冊(cè)了@RequestMapping方法就自動(dòng)下移,實(shí)際地址:項(xiàng)目名/h1/hello@RequestMapping("/hello")public String sayHello(Model model){//向模型中添加屬性msg與值,可以在JSP頁(yè)面中取出并渲染model.addAttribute("msg","hello,SpringMVCAnnotation!");//web-inf/jsp/hello.jspreturn "hello";} }- @Controller是為了讓Spring IOC容器初始化時(shí)自動(dòng)掃描到;
- @RequestMapping是為了映射請(qǐng)求路徑,這里因?yàn)轭惻c方法上都有映射所以訪問(wèn)時(shí)應(yīng)該是/h1/hello(一般規(guī)約是直接在方法上寫@RequestMapping("/h1/hello"),不建議在類上寫);
- 方法中聲明Model類型的參數(shù)是為了把Action中的數(shù)據(jù)帶到視圖中;
- 方法返回的結(jié)果是視圖的名稱hello,加上配置文件中的前后綴變成WEB-INF/jsp/hello.jsp
7、創(chuàng)建視圖層
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>SpringMVC</title> </head> <body> ${msg} </body> </html>在WEB-INF/ jsp目錄中創(chuàng)建hello.jsp , 視圖可以直接取出并展示從Controller帶回的信息;
可以通過(guò)EL表示取出Model中存放的值,或者對(duì)象;
8、配置Tomcat運(yùn)行
使用springMVC必須配置的三大件:
處理器映射器、處理器適配器、視圖解析器
通常,我們只需要手動(dòng)配置視圖解析器,而處理器映射器和處理器適配器只需要開(kāi)啟注解驅(qū)動(dòng)即可,而省去了大段的xml配置
再來(lái)回顧下原理吧~
4.控制器和RestFul風(fēng)格
控制器Controller
- 控制器復(fù)雜提供訪問(wèn)應(yīng)用程序的行為,通常通過(guò)接口定義或注解定義兩種方法實(shí)現(xiàn)。
- 控制器負(fù)責(zé)解析用戶的請(qǐng)求并將其轉(zhuǎn)換為一個(gè)模型。
- 在Spring MVC中一個(gè)控制器類可以包含多個(gè)方法
- 在Spring MVC中,對(duì)于Controller的配置方式有很多種
實(shí)現(xiàn)Controller接口
Controller是一個(gè)接口,在org.springframework.web.servlet.mvc包下,接口中只有一個(gè)方法;
//實(shí)現(xiàn)該接口的類獲得控制器功能 public interface Controller {//處理請(qǐng)求且返回一個(gè)模型與視圖對(duì)象ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception; }測(cè)試:
1、新建一個(gè)Moudle,springmvc-04-controller。將剛才的03 拷貝一份, 我們進(jìn)行操作!
2、刪掉HelloController。mvc的配置文件只留下視圖解析器!
3、編寫一個(gè)Controller類,ControllerTest
4、編寫完畢后,去Spring配置文件中注冊(cè)請(qǐng)求的bean;name對(duì)應(yīng)請(qǐng)求路徑,class對(duì)應(yīng)處理請(qǐng)求的類
<bean name="/t1" class="com.cheng.controller.ControllerTest1"/>5、編寫前端hello.jsp,注意在WEB-INF/jsp目錄下編寫,對(duì)應(yīng)我們的視圖解析器
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>hello</title> </head> <body> ${msg} </body> </html>6、配置Tomcat運(yùn)行測(cè)試
實(shí)現(xiàn)接口Controller定義控制器是較老的辦法,其缺點(diǎn)是:
一個(gè)控制器中只有一個(gè)方法,如果要多個(gè)方法則需要定義多個(gè)Controller;定義的方式比較麻煩;
使用注解@Controller
@Controller注解類型用于聲明Spring類的實(shí)例是一個(gè)控制器(在講IOC時(shí)還提到了另外3個(gè)注解);
Spring可以使用掃描機(jī)制來(lái)找到應(yīng)用程序中所有基于注解的控制器類,為了保證Spring能找到你的控制器,需要在配置文件中聲明組件掃描。
<!-- 自動(dòng)掃描指定的包,下面所有注解類交給IOC容器管理 --> <context:component-scan base-package="com.cheng.controller"/>增加一個(gè)ControllerTest2類,使用注解實(shí)現(xiàn);
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping;//@Controller注解的類會(huì)自動(dòng)添加到Spring上下文中 @Controller public class ControllerTest2{//映射訪問(wèn)路徑@RequestMapping("/t2")public String index(Model model){//Spring MVC會(huì)自動(dòng)實(shí)例化一個(gè)Model對(duì)象用于向視圖中傳值model.addAttribute("msg", "ControllerTest2");//返回視圖位置return "hello";} }運(yùn)行tomcat測(cè)試
可以發(fā)現(xiàn),我們的兩個(gè)請(qǐng)求都可以指向一個(gè)視圖,但是頁(yè)面結(jié)果的結(jié)果是不一樣的,從這里可以看出視圖是被復(fù)用的,而控制器與視圖之間是弱偶合關(guān)系。
注解方式是平時(shí)使用的最多的方式!
RequestMapping
@RequestMapping注解用于映射url到控制器類或一個(gè)特定的處理程序方法。可用于類或方法上。用于類上,表示類中的所有響應(yīng)請(qǐng)求的方法都是以該地址作為父路徑。
只注解在方法上面
@Controller public class TestController {@RequestMapping("/h1")public String test(){return "test";} }訪問(wèn)路徑:http://localhost:8080 / 項(xiàng)目名 / h1
同時(shí)注解類與方法
@Controller @RequestMapping("/admin") public class TestController {@RequestMapping("/h1")public String test(){return "test";} }訪問(wèn)路徑:http://localhost:8080 / 項(xiàng)目名/ admin /h1 , 需要先指定類的路徑再指定方法的路徑;
RestFul 風(fēng)格
概念
Restful就是一個(gè)資源定位及資源操作的風(fēng)格。不是標(biāo)準(zhǔn)也不是協(xié)議,只是一種風(fēng)格。基于這個(gè)風(fēng)格設(shè)計(jì)的軟件可以更簡(jiǎn)潔,更有層次,更易于實(shí)現(xiàn)緩存等機(jī)制。
功能
資源:互聯(lián)網(wǎng)所有的事物都可以被抽象為資源
資源操作:使用POST、DELETE、PUT、GET,使用不同方法對(duì)資源進(jìn)行操作。
分別對(duì)應(yīng) 添加、 刪除、修改、查詢。
傳統(tǒng)方式操作資源 :通過(guò)不同的參數(shù)來(lái)實(shí)現(xiàn)不同的效果!方法單一,post 和 get
? http://127.0.0.1/item/queryItem.action?id=1 查詢,GET
? http://127.0.0.1/item/saveItem.action 新增,POST
? http://127.0.0.1/item/updateItem.action 更新,POST
? http://127.0.0.1/item/deleteItem.action?id=1 刪除,GET或POST
使用RESTful操作資源 :可以通過(guò)不同的請(qǐng)求方式來(lái)實(shí)現(xiàn)不同的效果!如下:請(qǐng)求地址一樣,但是功能可以不同!
? http://127.0.0.1/item/1 查詢,GET
? http://127.0.0.1/item 新增,POST
? http://127.0.0.1/item 更新,PUT
? http://127.0.0.1/item/1 刪除,DELETE
學(xué)習(xí)測(cè)試
1、在新建一個(gè)類 RestFulController
@Controller public class RestFulController { }2、在Spring MVC中可以使用 @PathVariable 注解,讓方法參數(shù)的值對(duì)應(yīng)綁定到一個(gè)URI模板變量上。
@Controller public class RestFulController {//映射訪問(wèn)路徑@RequestMapping("/commit/{p1}/{p2}")public String index(@PathVariable int p1, @PathVariable int p2, Model model){int result = p1+p2;//Spring MVC會(huì)自動(dòng)實(shí)例化一個(gè)Model對(duì)象用于向視圖中傳值model.addAttribute("msg", "結(jié)果:"+result);//返回視圖位置return "hello"; } }3、測(cè)試
4、思考:使用路徑變量的好處?
- 使路徑變得更加簡(jiǎn)潔;
- 獲得參數(shù)更加方便,框架會(huì)自動(dòng)進(jìn)行類型轉(zhuǎn)換。
- 通過(guò)路徑變量的類型可以約束訪問(wèn)參數(shù),如果類型不一樣,則訪問(wèn)不到對(duì)應(yīng)的請(qǐng)求方法,如這里訪問(wèn)是的路徑是/commit/1/a,則路徑與方法不匹配,而不會(huì)是參數(shù)轉(zhuǎn)換失敗。
5、我們來(lái)修改下對(duì)應(yīng)的參數(shù)類型,再次測(cè)試
//映射訪問(wèn)路徑 @RequestMapping("/commit/{p1}/{p2}") public String index(@PathVariable int p1, @PathVariable String p2, Model model){String result = p1+p2;//Spring MVC會(huì)自動(dòng)實(shí)例化一個(gè)Model對(duì)象用于向視圖中傳值model.addAttribute("msg", "結(jié)果:"+result);//返回視圖位置return "hello"; }
Spring MVC 的 @RequestMapping 注解能夠處理 HTTP 請(qǐng)求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。
所有的地址欄請(qǐng)求默認(rèn)都會(huì)是 HTTP GET 類型的。
方法級(jí)別的注解變體有如下幾個(gè):組合注解
@GetMapping @PostMapping @PutMapping @DeleteMapping @PatchMapping@GetMapping 是一個(gè)組合注解,平時(shí)使用的會(huì)比較多!
它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一個(gè)快捷方式。
擴(kuò)展:小黃鴨調(diào)試法
場(chǎng)景一:我們都有過(guò)向別人(甚至可能向完全不會(huì)編程的人)提問(wèn)及解釋編程問(wèn)題的經(jīng)歷,但是很多時(shí)候就在我們解釋的過(guò)程中自己卻想到了問(wèn)題的解決方案,然后對(duì)方卻一臉茫然。
場(chǎng)景二:你的同行跑來(lái)問(wèn)你一個(gè)問(wèn)題,但是當(dāng)他自己把問(wèn)題說(shuō)完,或說(shuō)到一半的時(shí)候就想出答案走了,留下一臉茫然的你。
其實(shí)上面兩種場(chǎng)景現(xiàn)象就是所謂的小黃鴨調(diào)試法(Rubber Duck Debuging),又稱橡皮鴨調(diào)試法,它是我們軟件工程中最常使用調(diào)試方法之一。
此概念據(jù)說(shuō)來(lái)自《程序員修煉之道》書(shū)中的一個(gè)故事,傳說(shuō)程序大師隨身攜帶一只小黃鴨,在調(diào)試代碼的時(shí)候會(huì)在桌上放上這只小黃鴨,然后詳細(xì)地向鴨子解釋每行代碼,然后很快就將問(wèn)題定位修復(fù)了。
5.結(jié)果跳轉(zhuǎn)方式
ModelAndView
設(shè)置ModelAndView對(duì)象 , 根據(jù)view的名稱 , 和視圖解析器跳到指定的頁(yè)面 .
頁(yè)面 : {視圖解析器前綴} + viewName +{視圖解析器后綴}
<!-- 視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!-- 前綴 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后綴 --><property name="suffix" value=".jsp" /> </bean> public class ControllerTest implements Controller {public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {//返回一個(gè)模型視圖對(duì)象ModelAndView mv = new ModelAndView();mv.addObject("msg","Test1Controller");mv.setViewName("hello");return mv;} }ServletAPI
通過(guò)設(shè)置ServletAPI , 不需要視圖解析器(去把視圖解析器注釋掉)
1、通過(guò)HttpServletResponse進(jìn)行輸出
2、通過(guò)HttpServletResponse實(shí)現(xiàn)重定向
3、通過(guò)HttpServletRequest實(shí)現(xiàn)請(qǐng)求轉(zhuǎn)發(fā)
@Controller public class ResultGo {@RequestMapping("/r/t1")public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {rsp.getWriter().println("Hello,Spring by servlet API");}@RequestMapping("/r/t2")public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {rsp.sendRedirect("/index.jsp"); // 重定向}@RequestMapping("/r/t3")public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {//轉(zhuǎn)發(fā)req.setAttribute("msg","/r/t3");req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,rsp); // 請(qǐng)求轉(zhuǎn)發(fā)} }SpringMVC
1、無(wú)視圖解析器情況下通過(guò)SpringMVC來(lái)實(shí)現(xiàn)轉(zhuǎn)發(fā)和重定向。
測(cè)試前,需要將視圖解析器注釋掉
默認(rèn)為請(qǐng)求轉(zhuǎn)發(fā)forward(也可以加上)
重定向redirect需特別加
2、有視圖解析器情況下通過(guò)SpringMVC來(lái)實(shí)現(xiàn)轉(zhuǎn)發(fā)和重定向。
首先配置好視圖解析器
重定向 , 不需要視圖解析器 , 本質(zhì)就是重新請(qǐng)求一個(gè)新地方嘛 , 所以注意路徑問(wèn)題.
可以重定向到另外一個(gè)請(qǐng)求實(shí)現(xiàn) .
默認(rèn)為forward轉(zhuǎn)發(fā)(不可以加上)
因?yàn)橛幸晥D解析器的存在,如果加上(即forward:/hello.jsp)會(huì)被解析成為/WEB-INF/jsp/forward:/hello.jsp.jsp
redirect轉(zhuǎn)發(fā)需特別加
6.數(shù)據(jù)處理
處理提交數(shù)據(jù)
參數(shù)名一致
@Controller public class DataHandle {@RequestMapping("/hello")public String hello(String name){System.out.println(name);return "hello";} }提交數(shù)據(jù) : http://localhost:8080/hello?name=cheng
后臺(tái)輸出 : cheng
參數(shù)名不一致
提交的域名稱和處理方法的
//@RequestParam("username") : username提交的域的名稱 . @RequestMapping("/hello2") public String hello(@RequestParam("username") String name){System.out.println(name);return "hello"; }提交數(shù)據(jù) : http://localhost:8080/hello?username=cheng
后臺(tái)輸出 : cheng
提交的是一個(gè)對(duì)象
要求提交的表單域和對(duì)象的屬性名一致 , 參數(shù)使用對(duì)象即可
public class User {private int id;private String name;private int age;//構(gòu)造//get/set//toString() } @RequestMapping("/u") public String user(User user){System.out.println(user);return "hello"; }提交數(shù)據(jù) : http://localhost:8080/u/user?name=zxc&id=1&age=5
后臺(tái)輸出 : User { id=1, name=‘zxc’, age=15 }
說(shuō)明:如果使用對(duì)象的話,前端傳遞的參數(shù)名和對(duì)象名必須一致,否則就是null。
數(shù)據(jù)顯示到前端
第一種 : 通過(guò)ModelAndView
我們前面一直都是如此。就不過(guò)多解釋
第二種 : 通過(guò)ModelMap
ModelMap
@Controller public class DataDisplay {@RequestMapping("/dis")public String hello(@RequestParam("username") String name, ModelMap model){//封裝要顯示到視圖中的數(shù)據(jù)//相當(dāng)于req.setAttribute("name",name);model.addAttribute("msg",name);System.out.println(name);return "hello";} }http://localhost:8080/dis?username=qwe
第三種 : 通過(guò)Model
Model
@RequestMapping("/dis2")public String hello(@RequestParam("username") String name, Model model){//封裝要顯示到視圖中的數(shù)據(jù)//相當(dāng)于req.setAttribute("name",name);model.addAttribute("msg",name);System.out.println(name);return "hello";}http://localhost:8080/dis2?username=qwe
對(duì)比
就對(duì)于新手而言簡(jiǎn)單來(lái)說(shuō)使用區(qū)別就是:
Model 只有寥寥幾個(gè)方法只適合用于儲(chǔ)存數(shù)據(jù),簡(jiǎn)化了新手對(duì)于Model對(duì)象的操作和理解;ModelMap 繼承了 LinkedMap ,除了實(shí)現(xiàn)了自身的一些方法,同樣的繼承 LinkedMap 的方法和特性;ModelAndView 可以在儲(chǔ)存數(shù)據(jù)的同時(shí),可以進(jìn)行設(shè)置返回的邏輯視圖,進(jìn)行控制展示層的跳轉(zhuǎn)。 當(dāng)然更多的以后開(kāi)發(fā)考慮的更多的是性能和優(yōu)化,就不能單單僅限于此的了解。請(qǐng)使用80%的時(shí)間打好扎實(shí)的基礎(chǔ),剩下18%的時(shí)間研究框架,2%的時(shí)間去學(xué)點(diǎn)英文,框架的官方文檔永遠(yuǎn)是最好的教程。
7.亂碼問(wèn)題
測(cè)試步驟:
1、我們可以在首頁(yè)編寫一個(gè)提交的表單
<form action="/e/t" method="post"><input type="text" name="name"><input type="submit"> </form>2、后臺(tái)編寫對(duì)應(yīng)的處理類
@Controller public class Encoding {@RequestMapping("/e/t")public String test(Model model,String name){model.addAttribute("msg",name); //獲取表單提交的值return "hello"; //跳轉(zhuǎn)到test頁(yè)面顯示輸入的值} }3、輸入中文測(cè)試,發(fā)現(xiàn)亂碼
不得不說(shuō),亂碼問(wèn)題是在我們開(kāi)發(fā)中十分常見(jiàn)的問(wèn)題,也是讓我們比較頭大的問(wèn)題。
以前亂碼問(wèn)題通過(guò)過(guò)濾器解決 , 而SpringMVC給我們提供了一個(gè)過(guò)濾器 , 可以在web.xml中配置。
<filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param> </filter> <filter-mapping><filter-name>encoding</filter-name><url-pattern>/*</url-pattern> </filter-mapping>修改了xml文件需要重啟服務(wù)器。
注意/是過(guò)濾所有請(qǐng)求,/*包括jsp頁(yè)面也會(huì)過(guò)濾,因?yàn)閬y碼是顯示問(wèn)題,所以jsp也要加入到過(guò)濾當(dāng)中。
但是我們發(fā)現(xiàn),有些極端情況下,這個(gè)過(guò)濾器對(duì)get方法并不能解決亂碼問(wèn)題。
處理方法 :
1、修改tomcat配置文件 :設(shè)置編碼!
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />2、使用通用編碼過(guò)濾器類,見(jiàn)我另一篇文章
3、查看是不是客戶端顯示編碼有問(wèn)題。(如瀏覽器中右鍵-編碼-選擇Unicode(UTF-8))
8.JSON交互處理
什么是JSON?
- JSON(JavaScript Object Notation, JS 對(duì)象標(biāo)記) 是一種輕量級(jí)的數(shù)據(jù)交換格式,目前使用特別廣泛。
- 采用完全獨(dú)立于編程語(yǔ)言的文本格式來(lái)存儲(chǔ)和表示數(shù)據(jù)。
- 簡(jiǎn)潔和清晰的層次結(jié)構(gòu)使得 JSON 成為理想的數(shù)據(jù)交換語(yǔ)言。
- 易于人閱讀和編寫,同時(shí)也易于機(jī)器解析和生成,并有效地提升網(wǎng)絡(luò)傳輸效率。
- 在 JavaScript 語(yǔ)言中,一切都是對(duì)象。因此,任何JavaScript 支持的類型都可以通過(guò) JSON
來(lái)表示,例如字符串、數(shù)字、對(duì)象、數(shù)組等??纯此囊蠛驼Z(yǔ)法格式:
對(duì)象表示為鍵值對(duì),數(shù)據(jù)由逗號(hào)分隔
花括號(hào)保存對(duì)象
方括號(hào)保存數(shù)組
JSON 鍵值對(duì)是用來(lái)保存 JavaScript 對(duì)象的一種方式,和 JavaScript 對(duì)象的寫法也大同小異,鍵/值對(duì)組合中的鍵名寫在前面并用雙引號(hào) “” 包裹,使用冒號(hào) : 分隔,然后緊接著值:
{"name": "QinJiang"} {"age": "3"} {"sex": "男"}很多人搞不清楚 JSON 和 JavaScript 對(duì)象的關(guān)系,甚至連誰(shuí)是誰(shuí)都不清楚。其實(shí),可以這么理解:
JSON 是 JavaScript 對(duì)象的字符串表示法,它使用文本表示一個(gè) JS 對(duì)象的信息,本質(zhì)是一個(gè)字符串。
var obj = {a: 'Hello', b: 'World'}; //這是一個(gè)對(duì)象,注意鍵名也是可以使用引號(hào)包裹的 var json = '{"a": "Hello", "b": "World"}'; //這是一個(gè) JSON 字符串,本質(zhì)是一個(gè)字符串JSON 和 JavaScript 對(duì)象互轉(zhuǎn)
要實(shí)現(xiàn)從JSON字符串轉(zhuǎn)換為JavaScript 對(duì)象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //結(jié)果是 {a: 'Hello', b: 'World'}要實(shí)現(xiàn)從JavaScript 對(duì)象轉(zhuǎn)換為JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //結(jié)果是 '{"a": "Hello", "b": "World"}'代碼測(cè)試
1、新建一個(gè)module ,springmvc-05-json , 添加web的支持
2、在web目錄下新建一個(gè) json-1.html , 編寫測(cè)試內(nèi)容
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>JSON_test</title> </head> <body><script type="text/javascript">//編寫一個(gè)js的對(duì)象var user = {name:"張三",age:3,sex:"男"};//將js對(duì)象轉(zhuǎn)換成json字符串var str = JSON.stringify(user);console.log(str);//將json字符串轉(zhuǎn)換為js對(duì)象var user2 = JSON.parse(str);console.log(user2.age,user2.name,user2.sex);</script> </body> </html>3、在IDEA中使用瀏覽器打開(kāi),查看控制臺(tái)輸出!
JSON解析工具Jackson的使用
Jackson應(yīng)該是目前比較好的json解析工具了
當(dāng)然工具不止這一個(gè),比如還有阿里巴巴的 fastjson 等等。
1、導(dǎo)入它的jar包。
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.8</version> </dependency>2、將上一項(xiàng)目的web.xml的內(nèi)容和springmvc-servlet.xml文件拷過(guò)來(lái)。springmvc-servlet.xml內(nèi)容稍作修改
3、編寫一個(gè)User的實(shí)體類
4、編寫我們的測(cè)試Controller。這里我們需要兩個(gè)新東西,一個(gè)是 @ResponseBody,一個(gè)是ObjectMapper對(duì)象,我們看下具體的用法
@Controller public class UserController {@RequestMapping("/json")@ResponseBodypublic String json1() throws JsonProcessingException {//創(chuàng)建一個(gè)jackson的對(duì)象映射器,用來(lái)解析數(shù)據(jù)ObjectMapper mapper = new ObjectMapper();//創(chuàng)建一個(gè)對(duì)象User user = new User("長(zhǎng)江123", 3, "男");//將我們的對(duì)象解析成為json格式String str = mapper.writeValueAsString(user);//由于@ResponseBody注解,這里會(huì)將str轉(zhuǎn)成json格式返回;十分方便return str;} }配置Tomcat , 啟動(dòng)測(cè)試,發(fā)現(xiàn)出現(xiàn)亂碼
我們需要設(shè)置一下他的編碼格式為utf-8,以及它返回的類型。
通過(guò)@RequestMaping的produces屬性來(lái)實(shí)現(xiàn),修改下代碼
//produces:指定響應(yīng)體返回類型和編碼 @RequestMapping(value = "/json",produces = "application/json;charset=utf-8")亂碼問(wèn)題解決
JSON亂碼問(wèn)題
亂碼統(tǒng)一解決
上一種方法比較麻煩,如果項(xiàng)目中有許多請(qǐng)求則每一個(gè)都要添加,可以通過(guò)Spring配置統(tǒng)一指定,這樣就不用每次都去處理了!
我們可以在springmvc的配置文件上添加一段消息StringHttpMessageConverter轉(zhuǎn)換配置!
<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>統(tǒng)一解決返回的JSON字符串亂碼問(wèn)題
在類上直接使用 @RestController ,這樣子,里面所有的方法都只會(huì)返回 json 字符串了,不用再每一個(gè)都添加@ResponseBody 。我們?cè)谇昂蠖朔蛛x開(kāi)發(fā)中,一般都使用 @RestController ,十分便捷。
@RestController public class UserController {@RequestMapping(value = "/json")public String json1() throws JsonProcessingException {//創(chuàng)建一個(gè)jackson的對(duì)象映射器,用來(lái)解析數(shù)據(jù)ObjectMapper mapper = new ObjectMapper();//創(chuàng)建一個(gè)對(duì)象User user = new User("長(zhǎng)江123", 3, "男");//將我們的對(duì)象解析成為json格式String str = mapper.writeValueAsString(user);//由于@ResponseBody注解,這里會(huì)將str轉(zhuǎn)成json格式返回;十分方便return str;} }輸出JSON集合
增加一個(gè)新的方法
@RequestMapping("/json2") public String json2() throws JsonProcessingException {//創(chuàng)建一個(gè)jackson的對(duì)象映射器,用來(lái)解析數(shù)據(jù)ObjectMapper mapper = new ObjectMapper();//創(chuàng)建一個(gè)對(duì)象User user1 = new User("自行車1號(hào)", 3, "男");User user2 = new User("自行車2號(hào)", 3, "男");User user3 = new User("自行車3號(hào)", 3, "男");User user4 = new User("自行車4號(hào)", 3, "男");List<User> list = new ArrayList<User>();list.add(user1);list.add(user2);list.add(user3);list.add(user4);//將我們的對(duì)象解析成為json格式String str = mapper.writeValueAsString(list);return str; }輸出時(shí)間對(duì)象
增加一個(gè)新的方法
@RequestMapping("/json3") public String json3() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();//創(chuàng)建時(shí)間一個(gè)對(duì)象,java.util.DateDate date = new Date();//將我們的對(duì)象解析成為json格式String str = mapper.writeValueAsString(date);return str; }
默認(rèn)日期格式會(huì)變成一個(gè)數(shù)字,是1970年1月1日到當(dāng)前日期的毫秒數(shù)
Jackson 默認(rèn)是會(huì)把時(shí)間轉(zhuǎn)成timestamps形式
解決方案:取消timestamps形式 , 自定義時(shí)間格式
@RequestMapping("/json4") public String json4() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();//不使用時(shí)間戳的方式mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);//自定義日期格式對(duì)象SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//指定日期格式mapper.setDateFormat(sdf);Date date = new Date();String str = mapper.writeValueAsString(date);return str; }運(yùn)行結(jié)果 : 成功的輸出了時(shí)間
抽取為工具類
如果要經(jīng)常使用的話,這樣是比較麻煩的,我們可以將這些代碼封裝到一個(gè)工具類中;我們?nèi)ゾ帉懴?/p> package com.cheng.utils;import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature;import java.text.SimpleDateFormat;public class JsonUtils {public static String getJson(Object object) {return getJson(object,"yyyy-MM-dd HH:mm:ss");}public static String getJson(Object object,String dateFormat) {ObjectMapper mapper = new ObjectMapper();//不使用時(shí)間差的方式mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);//自定義日期格式對(duì)象SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);//指定日期格式mapper.setDateFormat(sdf);try {return mapper.writeValueAsString(object);} catch (JsonProcessingException e) {e.printStackTrace();}return null;} }
我們使用工具類,代碼就更加簡(jiǎn)潔了!
@RequestMapping("/json4") public String json4() throws JsonProcessingException {Date date = new Date();String json = JsonUtils.getJson(date);return json; }JSON解析工具FastJson的使用
fastjson.jar是阿里開(kāi)發(fā)的一款專門用于Java開(kāi)發(fā)的包,可以方便的實(shí)現(xiàn)json對(duì)象與JavaBean對(duì)象的轉(zhuǎn)換,實(shí)現(xiàn)JavaBean對(duì)象與json字符串的轉(zhuǎn)換,實(shí)現(xiàn)json對(duì)象與json字符串的轉(zhuǎn)換。實(shí)現(xiàn)json的轉(zhuǎn)換方法很多,最后的實(shí)現(xiàn)結(jié)果都是一樣的。
fastjson 的 pom依賴!
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.60</version> </dependency>Fastjson 三個(gè)主要的類:
JSONObject 代表 json 對(duì)象
-
JSON Object實(shí)現(xiàn)了Map接口, 猜想 JSONObject底層操作是由Map實(shí)現(xiàn)的。
-
JSONObject對(duì)應(yīng)json對(duì)象,通過(guò)各種形式的get()方法可以獲取json對(duì)象中的數(shù)據(jù),也可利用諸如size(),isEmpty()等方法獲取"鍵:值"對(duì)的個(gè)數(shù)和判斷是否為空。其本質(zhì)是通過(guò)實(shí)現(xiàn)Map接口并調(diào)用接口中的方法完成的。
JSONArray 代表 json 對(duì)象數(shù)組
- 內(nèi)部是有List接口中的方法來(lái)完成操作的。
JSON代表 JSONObject和JSONArray的轉(zhuǎn)化
- JSON類源碼分析與使用
- 仔細(xì)觀察這些方法,主要是實(shí)現(xiàn)json對(duì)象,json對(duì)象數(shù)組,javabean對(duì)象,json字符串之間的相互轉(zhuǎn)化。
代碼測(cè)試,我們新建一個(gè)FastJsonDemo 類
package com.cheng.controller;import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.cheng.pojo.User;import java.util.ArrayList; import java.util.List;public class FastJsonDemo {public static void main(String[] args) {//創(chuàng)建一個(gè)對(duì)象User user1 = new User("1號(hào)", 3, "男");User user2 = new User("2號(hào)", 3, "男");User user3 = new User("3號(hào)", 3, "男");User user4 = new User("4號(hào)", 3, "男");List<User> list = new ArrayList<User>();list.add(user1);list.add(user2);list.add(user3);list.add(user4);System.out.println("*******Java對(duì)象 轉(zhuǎn) JSON字符串*******");String str1 = JSON.toJSONString(list);System.out.println("JSON.toJSONString(list)==>"+str1);String str2 = JSON.toJSONString(user1);System.out.println("JSON.toJSONString(user1)==>"+str2);System.out.println("\n****** JSON字符串 轉(zhuǎn) Java對(duì)象*******");User jp_user1=JSON.parseObject(str2,User.class);System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);System.out.println("\n****** Java對(duì)象 轉(zhuǎn) JSON對(duì)象 ******");JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name"));System.out.println("\n****** JSON對(duì)象 轉(zhuǎn) Java對(duì)象 ******");User to_java_user = JSON.toJavaObject(jsonObject1, User.class);System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);} }輸出:
*******Java對(duì)象 轉(zhuǎn) JSON字符串******* JSON.toJSONString(list)==>[{"age":3,"name":"1號(hào)","sex":"男"},{"age":3,"name":"2號(hào)","sex":"男"},{"age":3,"name":"3號(hào)","sex":"男"},{"age":3,"name":"4號(hào)","sex":"男"}] JSON.toJSONString(user1)==>{"age":3,"name":"1號(hào)","sex":"男"}****** JSON字符串 轉(zhuǎn) Java對(duì)象******* JSON.parseObject(str2,User.class)==>User{name='1號(hào)', age=3, sex='男'}****** Java對(duì)象 轉(zhuǎn) JSON對(duì)象 ****** (JSONObject) JSON.toJSON(user2)==>2號(hào)****** JSON對(duì)象 轉(zhuǎn) Java對(duì)象 ****** JSON.toJavaObject(jsonObject1, User.class)==>User{name='2號(hào)', age=3, sex='男'}Process finished with exit code 0這種工具類,我們只需要掌握使用就好了,在使用的時(shí)候在根據(jù)具體的業(yè)務(wù)去找對(duì)應(yīng)的實(shí)現(xiàn)。和以前的commons-io那種工具包一樣,拿來(lái)用就好了。
Json在我們數(shù)據(jù)傳輸中十分重要,一定要學(xué)會(huì)使用!
9.AJAX
簡(jiǎn)介
- AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)。
- AJAX 是一種在無(wú)需重新加載整個(gè)網(wǎng)頁(yè)的情況下,能夠更新部分網(wǎng)頁(yè)的技術(shù)。
- Ajax 不是一種新的編程語(yǔ)言,而是一種用于創(chuàng)建更好更快以及交互性更強(qiáng)的Web應(yīng)用程序的技術(shù)。
- 在 2005 年,Google 通過(guò)其 Google Suggest 使 AJAX 變得流行起來(lái)。Google
Suggest能夠自動(dòng)幫你完成搜索單詞。 - Google Suggest 使用 AJAX 創(chuàng)造出動(dòng)態(tài)性極強(qiáng)的 web 界面:當(dāng)您在谷歌的搜索框輸入關(guān)鍵字時(shí),JavaScript會(huì)把這些字符發(fā)送到服務(wù)器,然后服務(wù)器會(huì)返回一個(gè)搜索建議的列表。就和國(guó)內(nèi)百度的搜索框一樣!
- 傳統(tǒng)的網(wǎng)頁(yè)(即不用ajax技術(shù)的網(wǎng)頁(yè)),想要更新內(nèi)容或者提交一個(gè)表單,都需要重新加載整個(gè)網(wǎng)頁(yè)。
- 使用ajax技術(shù)的網(wǎng)頁(yè),通過(guò)在后臺(tái)服務(wù)器進(jìn)行少量的數(shù)據(jù)交換,就可以實(shí)現(xiàn)異步局部更新。
- 使用Ajax,用戶可以創(chuàng)建接近本地桌面應(yīng)用的直接、高可用、更豐富、更動(dòng)態(tài)的Web用戶界面。
偽造Ajax
我們可以使用前端的一個(gè)標(biāo)簽來(lái)偽造一個(gè)ajax的樣子。iframe標(biāo)簽
1、新建一個(gè)module :springmvc-06-ajax , 導(dǎo)入web支持
2、編寫一個(gè) ajax-frame.html 使用 iframe 測(cè)試,感受下效果
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title>ajax-demo</title> </head> <body><script type="text/javascript">window.onload = function(){var myDate = new Date();document.getElementById('currentTime').innerText = myDate.getTime();};function LoadPage(){var targetUrl = document.getElementById('url').value;console.log(targetUrl);document.getElementById("iframePosition").src = targetUrl;}</script><div><p>請(qǐng)輸入要加載的地址:<span id="currentTime"></span></p><p><input id="url" type="text" value="https://www.baidu.com/"/><input type="button" value="提交" onclick="LoadPage()"></p> </div><div><h3>加載頁(yè)面位置:</h3><iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe> </div></body> </html>3、使用IDEA開(kāi)瀏覽器測(cè)試一下!
利用AJAX可以做:
- 注冊(cè)時(shí),輸入用戶名自動(dòng)檢測(cè)用戶是否已經(jīng)存在。
- 登陸時(shí),提示用戶名密碼錯(cuò)誤
- 刪除數(shù)據(jù)行時(shí),將行ID發(fā)送到后臺(tái),后臺(tái)在數(shù)據(jù)庫(kù)中刪除,數(shù)據(jù)庫(kù)刪除成功后,在頁(yè)面DOM中將數(shù)據(jù)行也刪除。
- …
jQuery.ajax
純JS原生實(shí)現(xiàn)Ajax我們不去講解這里,直接使用jquery提供的,方便學(xué)習(xí)和使用,避免重復(fù)造輪子,有興趣的同學(xué)可以去了解下JS原生XMLHttpRequest !
Ajax的核心是XMLHttpRequest對(duì)象(XHR)。XHR為向服務(wù)器發(fā)送請(qǐng)求和解析服務(wù)器響應(yīng)提供了接口。能夠以異步方式從服務(wù)器獲取新數(shù)據(jù)。
jQuery 提供多個(gè)與 AJAX 有關(guān)的方法。
通過(guò) jQuery AJAX 方法,您能夠使用 HTTP Get 和 HTTP Post 從遠(yuǎn)程服務(wù)器上請(qǐng)求文本、HTML、XML 或 JSON – 同時(shí)您能夠把這些外部數(shù)據(jù)直接載入網(wǎng)頁(yè)的被選元素中。
jQuery 不是生產(chǎn)者,而是大自然搬運(yùn)工。
jQuery Ajax本質(zhì)就是 XMLHttpRequest,對(duì)他進(jìn)行了封裝,方便調(diào)用!
jQuery.ajax(...)部分參數(shù):url:請(qǐng)求地址type:請(qǐng)求方式,GET、POST(1.9.0之后用method)headers:請(qǐng)求頭data:要發(fā)送的數(shù)據(jù)contentType:即將發(fā)送信息至服務(wù)器的內(nèi)容編碼類型(默認(rèn): "application/x-www-form-urlencoded; charset=UTF-8")async:是否異步timeout:設(shè)置請(qǐng)求超時(shí)時(shí)間(毫秒)beforeSend:發(fā)送請(qǐng)求前執(zhí)行的函數(shù)(全局)complete:完成之后執(zhí)行的回調(diào)函數(shù)(全局)success:成功之后執(zhí)行的回調(diào)函數(shù)(全局)error:失敗之后執(zhí)行的回調(diào)函數(shù)(全局)accepts:通過(guò)請(qǐng)求頭發(fā)送給服務(wù)器,告訴服務(wù)器當(dāng)前客戶端可接受的數(shù)據(jù)類型dataType:將服務(wù)器端返回的數(shù)據(jù)轉(zhuǎn)換成指定類型"xml": 將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成xml格式"text": 將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成普通文本格式"html": 將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成普通文本格式,在插入DOM中時(shí),如果包含JavaScript標(biāo)簽,則會(huì)嘗試去執(zhí)行。"script": 嘗試將返回值當(dāng)作JavaScript去執(zhí)行,然后再將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成普通文本格式"json": 將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成相應(yīng)的JavaScript對(duì)象"jsonp": JSONP 格式使用 JSONP 形式調(diào)用函數(shù)時(shí),如 "myurl?callback=?" jQuery 將自動(dòng)替換 ? 為正確的函數(shù)名,以執(zhí)行回調(diào)函數(shù)我們來(lái)個(gè)簡(jiǎn)單的測(cè)試,使用最原始的HttpServletResponse處理。最簡(jiǎn)單 , 最通用
10.攔截器
11.文件上傳和下載
總結(jié)
以上是生活随笔為你收集整理的Java学习笔记13-1——SpringMVC的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: angular-过滤器
- 下一篇: Java学习笔记5-1——多线程