《SpringMVC架構介紹》(建議收藏)
❤️希望博友給個三連+關注!!!
SSM: mybatis + Spring + SpringMVC MVC三層架構
SpringMVC + Vue + SpringBoot + SpringCloud + Linux
SSM = JavaWeb做項目;
Spring: IOC和APO
SpringMVC: SpringMVC的執行流程!
SpringMVC : SSM架構整合!
Spring
MVC:模型(dao, service) 視圖 (jsp)控制器 (Servlet)
dao
service
servlet :轉發,重定向
jsp/html
前端資料傳輸實體類
實體類:使用者名,密碼,生日,愛好,… 20個
前端:使用者名密碼
pojo: User
vo: UserVo
dto:
JSP:本質就是一個Servlet
假設:你的項目的架構,是設計好的,還是演進的? 演講
- Alibaba PHP
- 随着使用者大, Java
- 王堅去 IOE MySQL
- MySQL : MySQL–> AliSQL. AliRedis
- All in one -->微服務
MVC :
MWM: M V VM ViewModel :雙向綁定
1、什麼是MVC
- MVC是模型(Model)、視圖(View)、控制器(Controller)的簡寫,是一種軟體設計規範。
- 是将業務邏輯、資料、顯示分離的方法來組織代碼。
- MVC主要作用是降低了視圖與業務邏輯間的雙向偶合。
- MVC不是一種設計模式,MVC是一種架構模式。當然不同的MVC存在差異。
**Model(模型):**資料模型,提供要展示的資料,是以包含資料和行為,可以認為是領域模型或JavaBean元件(包含資料和行為),不過現在一般都分離開來:Value Object(資料Dao) 和 服務層(行為Service)。也就是模型提供了模型資料查詢和模型資料的狀态更新等功能,包括資料和業務。
**View(視圖):**負責進行模型的展示,一般就是我們見到的使用者界面,客戶想看到的東西。
**Controller(控制器):**接收使用者請求,委托給模型進行處理(狀态改變),處理完畢後把傳回的模型資料傳回給視圖,由視圖負責展示。 也就是說控制器做了個排程員的工作。
最典型的MVC就是JSP + servlet + javabean的模式。
1.1、Model1時代
- 在web早期的開發中,通常采用的都是Model1。
- Model1中,主要分為兩層,視圖層和模型層。
Model1優點:架構簡單,比較适合小型項目開發;
Model1缺點:JSP職責不單一,職責過重,不便于維護
1.2、Model2時代
Model2把一個項目分成三部分,包括視圖、控制、模型。
使用者發請求
- Servlet接收請求資料,并調用對應的業務邏輯方法
- 業務處理完畢,傳回更新後的資料給servlet
- servlet轉向到JSP,由JSP來渲染頁面
- 響應給前端更新後的頁面
職責分析:
Controller:控制器
- 取得表單資料
- 調用業務邏輯
- 轉向指定的頁面
Model:模型
- 業務邏輯
- 儲存資料的狀态
View:視圖
- 顯示頁面
Model2這樣不僅提高的代碼的複用率與項目的擴充性,且大大降低了項目的維護成本。Model 1模式的實作比較簡單,适用于快速開發小規模項目,Model1中JSP頁面身兼View和Controller兩種角色,将控制邏輯和表現邏輯混雜在一起,進而導緻代碼的重用性非常低,增加了應用的擴充性和維護的難度。Model2消除了Model1的缺點。
1.3、回顧Servlet
- 建立一個Maven工程當做父工程! pom依賴!
<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.建立一個Moudle:springmvc-01-servlet , 添加Web app的支援!
3.導入servlet 和 jsp 的 jar 依賴
<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>
4.編寫一個Servlet類,用來處理使用者的請求
package com.kk.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.擷取前端參數
String method = req.getParameter("method");
if (method.equals("add")){
req.getSession().setAttribute("msg","執行了add方法");
}
if (method.equals("delete")){
req.getSession().setAttribute("msg","執行了delete方法");
}
//2.調用業務層
//3.視圖轉發或者重定向
req.getRequestDispatcher("/WEB-INF/jsp/text.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
5.編寫Hello.jsp,在WEB-INF目錄下建立一個jsp的檔案夾,建立hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Kuangshen</title>
</head>
<body>
${msg}
</body>
</html>
6.在web.xml中注冊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>hello</servlet-name>
<servlet-class>com.kk.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!-- <session-config>-->
<!-- <session-timeout>15</session-timeout>-->
<!-- </session-config>-->
<!-- <welcome-file-list>-->
<!-- <welcome-file>index.jsp</welcome-file>-->
<!-- </welcome-file-list>-->
</web-app>
- 配置Tomcat,并啟動測試
- localhost:8080/user?method=add
- localhost:8080/user?method=delete
8.通路結果
MVC架構要做哪些事情
- 将url映射到java類或java類的方法 .
- 封裝使用者送出的資料 .
- 處理請求–調用相關的業務處理–封裝響應資料 .
- 将響應的資料進行渲染 . jsp / html 等表示層資料 .
說明:
常見的伺服器端MVC架構有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常見前端MVC架構:vue、angularjs、react、backbone;由MVC演化出了另外一些模式如:MVP、MVVM 等等…
2、什麼是SpringMVC
概述
Spring MVC是Spring Framework的一部分,是基于Java實作MVC的輕量級Web架構。
檢視官方文檔:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web
我們為什麼要學習SpringMVC呢?
Spring MVC的特點:
- 輕量級,簡單易學
- 高效 , 基于請求響應的MVC架構
- 與Spring相容性好,無縫結合
- 約定優于配置
- 功能強大:RESTful、資料驗證、格式化、本地化、主題等
- 簡潔靈活
Spring的web架構圍繞DispatcherServlet [ 排程Servlet ] 設計。
DispatcherServlet的作用是将請求分發到不同的處理器。從Spring 2.5開始,使用Java 5或者以上版本的使用者可以采用基于注解形式進行開發,十分簡潔;
正因為SpringMVC好 , 簡單 , 便捷 , 易學 , 天生和Spring無縫內建(使用SpringIoC和Aop) , 使用約定優于配置 . 能夠進行簡單的junit測試 . 支援Restful風格 .異常處理 , 本地化 , 國際化 , 資料驗證 , 類型轉換 , 攔截器 等等…是以我們要學習 .
最重要的一點還是用的人多 , 使用的公司多 .
中心控制器
Spring的web架構圍繞DispatcherServlet設計。 DispatcherServlet的作用是将請求分發到不同的處理器。從Spring 2.5開始,使用Java 5或者以上版本的使用者可以采用基于注解的controller聲明方式。
Spring MVC架構像許多其他MVC架構一樣, 以請求為驅動 , 圍繞一個中心Servlet分派請求及提供其他功能,DispatcherServlet是一個實際的Servlet (它繼承自HttpServlet 基類)。
圖來源:狂神說,如有侵權,請聯系删除!
SpringMVC的原理如下圖所示:
當發起請求時被前置的控制器攔截到請求,根據請求參數生成代理請求,找到請求對應的實際控制器,控制器處理請求,建立資料模型,通路資料庫,将模型響應給中心控制器,控制器使用模型與視圖渲染視圖結果,将結果傳回給中心控制器,再将結果傳回給請求者。
圖來源:狂神說,如有侵權,請聯系删除!
SpringMVC執行原理
圖來源:狂神說,如有侵權,請聯系删除!
圖為SpringMVC的一個較完整的流程圖,實線表示SpringMVC架構提供的技術,不需要開發者實作,虛線表示需要開發者實作。
簡要分析執行流程
- DispatcherServlet表示前置控制器,是整個SpringMVC的控制中心。使用者送出請求,DispatcherServlet接收請求并攔截請求。
- 我們假設請求的url為 :http://localhost:8080/SpringMVC/hello
- 如上url拆分成三部分:
- http://localhost:8080伺服器域名
- SpringMVC部署在伺服器上的web站點
- hello表示控制器
- 通過分析,如上url表示為:請求位于伺服器localhost:8080上的SpringMVC站點的hello控制器。
- HandlerMapping為處理器映射。DispatcherServlet調用HandlerMapping,HandlerMapping根據請求url查找Handler。
- HandlerExecution表示具體的Handler,其主要作用是根據url查找控制器,如上url被查找控制器為:hello。
- HandlerExecution将解析後的資訊傳遞給DispatcherServlet,如解析控制器映射等。
- HandlerAdapter表示處理器擴充卡,其按照特定的規則去執行Handler。
- Handler讓具體的Controller執行。
- Controller将具體的執行資訊傳回給HandlerAdapter,如ModelAndView。
- HandlerAdapter将視圖邏輯名或模型傳遞給DispatcherServlet。
- DispatcherServlet調用視圖解析器(ViewResolver)來解析HandlerAdapter傳遞的邏輯視圖名。
- 視圖解析器将解析的邏輯視圖名傳給DispatcherServlet。
- DispatcherServlet根據視圖解析器解析的視圖結果,調用具體的視圖。
- 最終視圖呈現給使用者。
3、HelloSpringMVC(配置版)
3.1、建立一個Moudle , 添加web的支援!
3.2、确定導入了SpringMVC 的依賴!
3.3、配置web.xml , 注冊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">
<!-- 配置DispatchServlet:這個是MVC的核心;也叫請求分發器,或前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispatchServlet要綁定SpringMVC的配置檔案-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-serlvet.xml</param-value>
</init-param>
<!-- 啟動級别-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--
在SpringMVC中 / /*
/ :隻比對所有的請求,不會去比對jsp頁面
/* :比對所有的請求,包括jsp頁面
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.4、編寫SpringMVC 的 配置檔案!名稱:springmvc-servlet.xml : [servletname]-servlet.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
3.5、添加 處理映射器
3.6、添加 處理器擴充卡
3.7、添加 視圖解析器
如下:
<?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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 處理器映射器-->
<!-- 從這開始執行,BeanNameUrlHandlerMapping:bean找到/hello..找到對應的類-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 處理器擴充卡-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 視圖解析器;模闆引擎Thymeleaf Fremarker-->
<!--視圖解析器:DispatcherServlet給他的ModelAndView-->
<!-- 傳回的 ModelAndView交給視圖解析器去做-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 字首-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 字尾-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- BeanNameUrlHandlerMapping:bean-->
<bean id="/hello" class="com.kk.controller.HelloController"></bean>
</beans>
3.8、編寫我們要操作業務Controller ,要麼實作Controller接口,要麼增加注解;需要傳回一個ModelAndView,裝資料,封視圖;
package com.kk.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//注意:這裡我們先導入Controller接口
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModelAndView 模型和視圖
ModelAndView mv = new ModelAndView();
//封裝對象,放在ModelAndView中。Model
mv.addObject("msg", "HelloSpringMVC!");
//封裝要跳轉的視圖,放在ModelAndView中
mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
return mv;
}
}
3.9、将自己的類交給SpringIOC容器(寫到springmvc-servlet.xml),注冊bean
<!--Handler-->
<bean id="/hello" class="com.kuang.controller.HelloController"/>
3.10、寫要跳轉的jsp頁面,顯示ModelandView存放的資料,以及我們的正常頁面;
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
3.1.1、配置Tomcat 啟動測試!
可能遇到的問題:通路出現404,排查步驟:
- 檢視控制台輸出,看一下是不是缺少了什麼jar包。
- 如果jar包存在,顯示無法輸出,就在IDEA的項目釋出中,添加lib依賴!(與classes同級目錄)
**小結**:看這個估計大部分同學都能了解其中的原理了,但是我們實際開發才不會這麼寫,不然就瘋了,還學這個玩意幹嘛!我們來看個注解版實作,這才是SpringMVC的精髓,到底有多麼簡單,看這個圖就知道了。
圖來源:狂神說,如有侵權,請聯系删除!
4、使用注解開發SpringMVC(注解版)
4.1、第一步:建立一個Moudle , 添加web支援!建立包結構 com.kk.controller
4.2、第二步:由于Maven可能存在資源過濾的問題,我們将配置完善
<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>
4.3、第三步:在pom.xml檔案引入相關的依賴:
主要有Spring架構核心庫、Spring MVC、servlet , JSTL等。我們在父依賴中已經引入了!
4.4、第四步:配置web.xml
注意點:
- 注意web.xml版本問題,要最新版!
- 注冊DispatcherServlet
- 關聯SpringMVC的配置檔案
- 啟動級别為1
- 映射路徑為 / 【不要用/*,會404】
4.5、第五步:添加Spring MVC配置檔案
- 讓IOC的注解生效
- 靜态資源過濾 :HTML . JS . CSS . 圖檔 , 視訊 …
- MVC的注解驅動
- 配置視圖解析器
在resource目錄下添加springmvc-servlet.xml配置檔案,配置的形式與Spring容器配置基本類似,為了支援基于注解的IOC,設定了自動掃描包的功能,具體配置資訊如下:
<?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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自動掃描包,讓指定包下的注解生效,由IOC容器統一管理 -->
<context:component-scan base-package="com.kk.controller"/>
<!-- 讓Spring MVC不處理靜态資源 過濾掉一些靜态資源,如.css .js .html .mp3-->
<mvc:default-servlet-handler />
<!--
支援mvc注解驅動
在spring中一般采用@RequestMapping注解來完成映射關系
要想使@RequestMapping注解生效
必須向上下文中注冊DefaultAnnotationHandlerMapping
和一個AnnotationMethodHandlerAdapter執行個體
這兩個執行個體分别在類級别和方法級别處理。
而annotation-driven配置幫助我們自動完成上述兩個執行個體的注入。
-->
<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>
在視圖解析器中我們把所有的視圖都存放在/WEB-INF/目錄下,這樣可以保證視圖安全,因為這個目錄下的檔案,用戶端不能直接通路。
4.6、第六步:建立Controller
編寫一個Java控制類: com.kuang.controller.HelloController , 注意編碼規範
package com.kk.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(Model model){
//封裝資料
model.addAttribute("msg","Hello SpringMVCAnnotation");
return "hello"; //這個會被視圖解析器處理;
}
}
- @Controller是為了讓Spring IOC容器初始化時自動掃描到;
- @RequestMapping是為了映射請求路徑,這裡因為類與方法上都有映射是以通路時應該是/HelloController/hello;
- 方法中聲明Model類型的參數是為了把Action中的資料帶到視圖中;
- 方法傳回的結果是視圖的名稱hello,加上配置檔案中的前字尾變成WEB-INF/jsp/hello.jsp。
4.7、第七步:建立視圖層
在WEB-INF/ jsp目錄中建立hello.jsp , 視圖可以直接取出并展示從Controller帶回的資訊;
可以通過EL表示取出Model中存放的值,或者對象;
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>SpringMVC</title>
</head>
<body>
${msg}
</body>
</html>
4.8、第八步:配置Tomcat運作
配置Tomcat , 開啟伺服器 , 通路 對應的請求路徑!
運作成功!
小結
實作步驟非常的簡單:
- 建立一個web項目
- 導入相關jar包
- 編寫web.xml , 注冊DispatcherServlet
- 編寫springmvc配置檔案
- 接下來就是去建立對應的控制類 , controller
- 最後完善前端視圖和controller之間的對應
- 測試運作調試.
使用springMVC必須配置的三大件:
處理器映射器、處理器擴充卡、視圖解析器
通常,我們隻需要手動配置視圖解析器,而處理器映射器和處理器擴充卡隻需要開啟注解驅動即可,而省去了大段的xml配置
5、Controller 及 RestFul風格
控制器Controller
- 控制器複雜提供通路應用程式的行為,通常通過接口定義或注解定義兩種方法實作。
- 控制器負責解析使用者的請求并将其轉換為一個模型。
- 在Spring MVC中一個控制器類可以包含多個方法
-
在Spring MVC中,對于Controller的配置方式有很多種
我們來看看有哪些方式可以實作:
實作Controller接口
//實作該接口的類獲得控制器功能
public interface Controller {
//處理請求且傳回一個模型與視圖對象
ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
測試
- 建立一個Moudle,springmvc-04-controller 。 将剛才的03 拷貝一份, 我們進行操作!
- 删掉HelloController
- mvc的配置檔案隻留下 視圖解析器!
- 編寫一個Controller類,ControllerTest1
package com.kk.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//隻要實作了Controller接口的類,說明這就是一個控制器了
public class ControllerTest01 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest01!"); //添加資料
mv.setViewName("test"); //設定跳轉視圖 跳轉到哪 由這個控制 如 跳轉到test(.jps頁面)
return mv;
}
}
編寫完畢後,去Spring配置檔案中注冊請求的bean;name對應請求路徑,class對應處理請求的類
<bean name="/test" class="com.kk.controller.ControllerTest01"/>
編寫前端test.jsp,注意在WEB-INF/jsp目錄下編寫,對應我們的視圖解析器
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
配置Tomcat運作測試,我這裡沒有項目釋出名配置的就是一個 / ,是以請求不用加項目名;
說明:
- 實作接口Controller定義控制器是較老的辦法
- 缺點是:一個控制器中隻有一個方法,如果要多個方法則需要定義多個Controller;定義的方式比較麻煩;
使用注解@Controller
- @Controller注解類型用于聲明Spring類的執行個體是一個控制器(在講IOC時還提到了另外3個注解);
- Spring可以使用掃描機制來找到應用程式中所有基于注解的控制器類,為了保證Spring能找到你的控制器,需要在配置檔案中聲明元件掃描。
<context:component-scan base-package="com.kk.controller"/>
增加一個ControllerTest2類,使用注解實作;
package com.kk.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller //代表這個類會被Spring接管,被這個注解的類,中的所有方法,
// 如果傳回值是String 并且有具體頁面可以跳轉,那麼就會被視圖解析器解析;
public class ControllerTest02{
@RequestMapping("/test2")
public String test1(Model model){
model.addAttribute("msg","ControllerTest02!");
return "test";
}
}
運作tomcat測試
可以發現,我們的兩個請求都可以指向一個視圖,但是頁面結果的結果是不一樣的,從這裡可以看出視圖是被複用的,而控制器與視圖之間是弱偶合關系。
RequestMapping
@RequestMapping
- @RequestMapping注解用于映射url到控制器類或一個特定的處理程式方法。可用于類或方法上。用于類上,表示類中的所有響應請求的方法都是以該位址作為父路徑。
package com.kk.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("c3")
public class ControllerTest03 {
@RequestMapping("t1")
public String test1(Model model){
model.addAttribute("msg","ControllerTest03");
return "test";
}
}
通路路徑:http://localhost:8080 /c3/t1 , 需要先指定類的路徑再指定方法的路徑;
6、RestFul 風格(簡潔,高效,安全)
概念
Restful就是一個資源定位及資源操作的風格。不是标準也不是協定,隻是一種風格。基于這個風格設計的軟體可以更簡潔,更有層次,更易于實作緩存等機制。
功能
- 資源:網際網路所有的事物都可以被抽象為資源
- 資源操作:使用POST、DELETE、PUT、GET,使用不同方法對資源進行操作。
- 分别對應 添加、 删除、修改、查詢。
傳統方式操作資源 :通過不同的參數來實作不同的效果!方法單一,post 和 get
測試1:
1.在建立一個類 RestFulController
package com.kk.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RestFulController {
//原來的方式 http://localhost:8080/add?a=1&b=10
@RequestMapping("/add")
public String test1(int a, int b, Model model){
int res=a+b;
model.addAttribute("msg","結果為:"+res);
return "test";
}
}
測試2:
2.在Spring MVC中可以使用 @PathVariable 注解,讓方法參數的值對應綁定到一個URI模闆變量上。
package com.kk.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RestFulController {
// RestFul http://localhost:8080/add/a/b
@RequestMapping("/add/{a}/{b}")
public String test1(@PathVariable int a,@PathVariable int b, Model model){
int res=a+b;
model.addAttribute("msg","結果為:"+res);
return "test";
}
}
思考:使用路徑變量的好處?
- 使路徑變得更加簡潔;
- 獲得參數更加友善,架構會自動進行類型轉換。
- 通過路徑變量的類型可以限制通路參數,如果類型不一樣,則通路不到對應的請求方法,如這裡通路是的路徑是/commit/1/a,則路徑與方法不比對,而不會是參數轉換失敗。
圖來源:狂神說,如有侵權,請聯系删除!
我們來修改下對應的參數類型,再次測試
@Controller
public class RestFulController {
@PostMapping("/add/{a}/{b}")
public String test1(@PathVariable int a,@PathVariable String b, Model model){
// int res=a+b;
String res=a+b;
model.addAttribute("msg","結果1為:"+res);
return "test";
}
}
圖來源:狂神說,如有侵權,請聯系删除!
使用method屬性指定請求類型
用于限制請求的類型,可以收窄請求範圍。指定請求謂詞的類型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等
我們來測試一下:
- 增加一個方法
//映射通路路徑,必須是POST請求
@RequestMapping(value = "/hello",method = {RequestMethod.POST})
public String test(Model model){
model.addAttribute("msg", "hello!");
return "test";
}
我們使用浏覽器位址欄進行通路預設是Get請求,會報錯405:
圖來源:狂神說,如有侵權,請聯系删除!
如果将POST修改為GET則正常了;
//映射通路路徑,必須是Get請求
@RequestMapping(value = "/hello",method = {RequestMethod.GET})
public String test(Model model){
model.addAttribute("msg", "hello!");
return "test";
}
圖來源:狂神說,如有侵權,請聯系删除!
小結:
Spring MVC 的 @RequestMapping 注解能夠處理 HTTP 請求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。
所有的位址欄請求預設都會是 HTTP GET 類型的
方法級别的注解變體有如下幾個: 組合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping 是一個組合注解
@Controller
public class RestFulController {
//映射通路路徑
@GetMapping("/commit/{a}/{b}")
public String test2(@PathVariable int a,@PathVariable String b, Model model){
String res=a+b;
model.addAttribute("msg","結果2為:"+res);
return "test";
}
}
7、SpringMVC:結果跳轉三種方式(轉發、重定向)
7.1、ModelAndView
設定ModelAndView對象 , 根據view的名稱 , 和視圖解析器跳到指定的頁面 .
頁面 : {視圖解析器字首} + viewName +{視圖解析器字尾}
<!-- 視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 字首 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 字尾 -->
<property name="suffix" value=".jsp" />
</bean>
對應的controller類
public class ControllerTest01 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//傳回一個模型視圖對象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest01");
mv.setViewName("test");
return mv;
}
}
7.2、ServletAPI
通過設定ServletAPI , 不需要視圖解析器 .
- 通過HttpServletResponse進行輸出
- 通過HttpServletResponse實作重定向
- 通過HttpServletResponse實作轉發
@Controller
public class ResultGo {
@RequestMapping("/m1/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.getWriter().println("Hello,Spring BY servlet API");
}
@RequestMapping("/m2/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.sendRedirect("/index.jsp");
}
@RequestMapping("/m3/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//轉發
req.setAttribute("msg","/m3/t3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}
}
7.3、SpringMVC
通過SpringMVC來實作轉發和重定向 - 無需視圖解析器;
測試前,需要将視圖解析器注釋掉
package com.kk.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class ModelTest01 {
// @RequestMapping("/m1/t1")
// public String test(HttpServletRequest request, HttpServletResponse response){
// HttpSession session = request.getSession();
// System.out.println(session.getId());
//
// return "/test.jsp";
// }
// @RequestMapping("/m1/t1")
// public String test(Model model){
// model.addAttribute("msg","ModelTest01");
// //轉發
// return "forward:/WEB-INF/jsp/test.jsp";
// }
//http://localhost:8080/index.jsp?msg=ModelTest01
@RequestMapping("/m1/t1")
public String test2(Model model){
model.addAttribute("msg","ModelTest01");
//重定向
return "redirect:/index.jsp";
}
}
通過SpringMVC來實作轉發和重定向 - 有視圖解析器;
重定向 , 不需要視圖解析器 , 本質就是重新請求一個新地方嘛 , 是以注意路徑問題.
可以重定向到另外一個請求實作 .
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/m1/t1")
public String test1(){
//轉發
return "test";
}
@RequestMapping("/m2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
//return "redirect:hello.do"; /
/hello.do為另一個請求/
}
}
8、資料處理(接收請求參數及資料回顯)
8.1、處理送出資料
1、送出的域名稱和處理方法的參數名一緻
送出資料 : http://localhost:8080/user/t1?name=dada
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/t1")
public String test(tring name, Model model){
//1.接收前端參數
System.out.println("接收到前端的參數為為:"+name);
//2.将傳回的結果傳遞給前端 Model
model.addAttribute("msg",name);
//3.視圖傳遞
return "test";
}
}
背景輸出 : dada
2、送出的域名稱和處理方法的參數名不一緻
送出資料 : http://localhost:8080/user/t1?username=dada
處理方法 :
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/t1")
public String test(@RequestParam("username") String name, Model model){
//1.接收前端參數
System.out.println("接收到前端的參數為為:"+name);
//2.将傳回的結果傳遞給前端 Model
model.addAttribute("msg",name);
//3.視圖傳遞
return "test";
}
}
背景輸出 :
要求送出的表單域和對象的屬性名一緻 , 參數使用對象即可
1.實體類
package com.kk.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
private int id;
private String name;
private int age;
}
處理方法 :
package com.kk.controller;
import com.kk.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/user")
public class UserController {
//前端接收的是一個對象 id name age
/*
1.接收前端使用者傳遞的參數,判斷參數的名字,假設名字直接在方法上,可以直接使用
2.假設傳遞的是一個對象User 比對User對象中的字段名,如果名字一直則ok 否則比對不到
*/
@GetMapping("/t2")
public String test2(User user){
System.out.println(user);
return "test";
}
}
送出資料:http://localhost:8080/user/t2?id=1&name=王&age=17
背景輸出:User{id=1, name=‘王’, age=17}
8.2、資料顯示到前端
第一種 : 通過ModelAndView
public class ControllerTest01 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//傳回一個模型視圖對象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest01");
mv.setViewName("test");
return mv;
}
}
第二種 : 通過ModelMap
ModelMap
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
//封裝要顯示到視圖中的資料
//相當于req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "hello";
}
第三種 : 通過Model
Model
@RequestMapping("/m1/t1")
public String hello(@RequestParam("username") String name, Model model){
//封裝要顯示到視圖中的資料
//相當于req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}
8.3、對比
就對于新手而言簡單來說使用差別就是:
Model 隻有寥寥幾個方法隻适合用于儲存資料,簡化了新手對于Model對象的操作和了解;
ModelMap 繼承了 LinkedMap ,除了實作了自身的一些方法,同樣的繼承 LinkedMap 的方法和特性;
ModelAndView 可以在儲存資料的同時,可以進行設定傳回的邏輯視圖,進行控制展示層的跳轉。
9、資料處理(亂碼問題)
測試步驟:
1.我們可以在首頁編寫一個送出的表單
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/e/t1" method="post">
<input type="text" name="name">
<input type="submit">
</form>
</body>
</html>
2.背景編寫對應的處理類
@Controller
public class EncodingController {
@RequestMapping("/e/t1")
public String test1(String name, Model model){
System.out.println(name);
model.addAttribute("msg",name);//使用視圖解析器,将資料傳遞到return test(即test.jsp頁面)
return "test";
}
}
3.輸入中文測試,發現亂碼
不得不說,亂碼問題是在我們開發中十分常見的問題,也是讓我們程式猿比較頭大的問題!
以前亂碼問題通過過濾器解決 , 而SpringMVC給我們提供了一個過濾器 , 可以在web.xml中配置 .
修改了xml檔案需要重新開機伺服器!
<!--2.配置SpringMVC的亂碼過濾-->
<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>
有些極端情況下.這個過濾器對get的支援不好 .
處理方法 :
1.修改tomcat配置檔案 : 設定編碼!
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
2.自定義過濾器
package com.kk.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
public class GenericEncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("===========================");
//處理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);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
//自定義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;
}
}
3.在web中注冊:
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.kk.filter.GenericEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
這個也是我在網上找的一些大神寫的,一般情況下,SpringMVC預設的亂碼處理就已經能夠很好的解決了!
平常使用SringMVC過濾器即可,在web中注冊!
<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>
10、JSON講解
9.1、什麼是JSON?
- JSON(JavaScript Object Notation, JS 對象标記) 是一種輕量級的資料交換格式,目前使用特别廣泛。
- 采用完全獨立于程式設計語言的文本格式來存儲和表示資料。
- 簡潔和清晰的層次結構使得 JSON 成為理想的資料交換語言。
- 易于人閱讀和編寫,同時也易于機器解析和生成,并有效地提升網絡傳輸效率。
在 JavaScript 語言中,一切都是對象。是以,任何JavaScript 支援的類型都可以通過 JSON 來表示,例如字元串、數字、對象、數組等。看看他的要求和文法格式:
- 對象表示為鍵值對,資料由逗号分隔
- 花括号儲存對象
- 方括号儲存數組
JSON 鍵值對是用來儲存 JavaScript 對象的一種方式,和 JavaScript 對象的寫法也大同小異,鍵/值對組合中的鍵名寫在前面并用雙引号 “” 包裹,使用冒号 : 分隔,然後緊接着值:
{"name": "kk"}
{"age": "17"}
{"sex": "男"}
JSON 是 JavaScript 對象的字元串表示法,它使用文本表示一個 JS 對象的資訊,本質是一個字元串
var obj = {a: 'Hello', b: 'World'}; //這是一個對象,注意鍵名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}'; //這是一個 JSON 字元串,本質是一個字元串
JSON 和 JavaScript 對象互轉
- 要實作從JSON字元串轉換為JavaScript 對象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}');
//結果是 {a: 'Hello', b: 'World'}
- 要實作從JavaScript 對象轉換為JSON字元串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'});
//結果是 '{"a": "Hello", "b": "World"}'
代碼測試
1.建立一個module ,springmvc-05-json , 添加web的支援
2.在web目錄下建立一個 json-1.html , 編寫測試内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">//編寫與一個JavaScript對象
var user={
name:"小白",
age:17,
sex:"男"
};
//将js對象轉換為json對象
var json=JSON.stringify(user);
console.log(json);
console.log("========================");
//将json對象轉換為JavaScript對象
var obj=JSON.parse(json);
console.log(obj);</script>
</head>
<body>
</body>
</html>
3.在IDEA中使用浏覽器打開,檢視控制台輸出!
9.2、Controller傳回JSON資料
1.jackson
- Jackson應該是目前比較好的json解析工具了
- 當然工具不止這一個,比如還有阿裡巴巴的 fastjson 等等。
- 我們這裡使用Jackson,使用它需要導入它的jar包;
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
-
配置SpringMVC需要的配置
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">
<!--1.注冊servlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通過初始化參數指定SpringMVC配置檔案的位置,進行關聯-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 啟動順序,數字越小,啟動越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有請求都會被springmvc攔截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
</web-app>
springmvc-servlet.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"
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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自動掃描指定的包,下面所有注解類交給IOC容器管理 -->
<context:component-scan base-package="com.kuang.controller"/>
<!-- 視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 字首 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 字尾 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
我們随便編寫一個User的實體類,然後我們去編寫我們的測試Controller;
public class User {
private String name;
private int age;
private String sex;
public User() {
}
public User(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
- 這裡我們需要兩個新東西,一個是@ResponseBody,一個是ObjectMapper對象,我們看下具體的用法
Controller
package com.kk.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kk.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
@RequestMapping("/j1")
@ResponseBody //隻要增加了ResponseBody 它就不會走試圖解析器,會直接傳回一個字元串
public String Json1() throws JsonProcessingException {
//jackson ObjectMapper
ObjectMapper mapper=new ObjectMapper();
//建立一個對象
User user = new User("1号",17,"男");
//将user轉換為Json
String str = mapper.writeValueAsString(user);
return str;
}
}
- 配置Tomcat , 啟動測試一下!
- 發現出現了亂碼問題,我們需要設定一下他的編碼格式為utf-8,以及它傳回的類型;
- 通過@RequestMaping的produces屬性來實作,修改下代碼
//produces:指定響應體傳回類型和編碼
@RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")
- 再次測試,http://localhost:8080/j1 , 亂碼問題OK!
【注意:使用json記得處理亂碼問題】
代碼優化
亂碼統一解決
上一種方法比較麻煩,如果項目中有許多請求則每一個都要添加,可以通過Spring配置統一指定,這樣就不用每次都去處理了!
我們可以在springmvc的配置檔案上添加一段消息StringHttpMessageConverter轉換配置!
<!--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>
傳回json字元串統一解決
在類上直接使用 @RestController ,這樣子,裡面所有的方法都隻會傳回 json 字元串了,不用再每一個都添加@ResponseBody !我們在前後端分離開發中,一般都使用 @RestController ,十分便捷!
//@Controller 會調用視圖解析器
@RestController //會傳回字元串
public class UserController {
// @RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")
@RequestMapping(value = "/j1")
// @ResponseBody //隻要增加了ResponseBody 它就不會走試圖解析器,會直接傳回一個字元串
//使用了RestController就不用ResponseBody了
public String Json1() throws JsonProcessingException {
//jackson ObjectMapper
ObjectMapper mapper=new ObjectMapper();
//建立一個對象
User user = new User("1号",17,"男");
//将user轉換為Json
String str = mapper.writeValueAsString(user);
return str;
}
}
啟動tomcat測試,結果都正常輸出!
測試集合輸出
增加一個新的方法
//@Controller 會調用視圖解析器
@RestController //會傳回字元串
public class UserController {
// @RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")
@RequestMapping(value = "/j1")
// @ResponseBody //隻要增加了ResponseBody 它就不會走試圖解析器,會直接傳回一個字元串
//使用了RestController就不用ResponseBody了
public String Json1() throws JsonProcessingException {
//jackson ObjectMapper
ObjectMapper mapper=new ObjectMapper();
//建立一個對象
User user = new User("1号",17,"男");
//将user轉換為Json
String str = mapper.writeValueAsString(user);
return str;
}
@RequestMapping(value = "/j2")
public String Json2() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
//使用集合
List<User> userList=new ArrayList<User>();
User user1 = new User("1号",17,"男");
User user2 = new User("1号",17,"男");
User user3 = new User("1号",17,"男");
User user4 = new User("1号",17,"男");
User user5 = new User("1号",17,"男");
User user6 = new User("1号",17,"男");
User user7 = new User("1号",17,"男");
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.add(user5);
userList.add(user6);
userList.add(user7);
String str = mapper.writeValueAsString(userList);
return str;
}
}
啟動tomcat測試,結果都正常輸出!
輸出時間對象
增加一個新的方法
@RequestMapping("/json3")
public String json3() throws JsonProcessingException {
@RequestMapping("/j3")
public String json3() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//建立時間一個對象,java.util.Date
Date date = new Date();
//将我們的對象解析成為json格式
String str = mapper.writeValueAsString(date);
return str;
}
}
運作結果 :
- 預設日期格式會變成一個數字,是1970年1月1日到目前日期的毫秒數!
- Jackson 預設是會把時間轉成timestamps形式
解決方案:取消timestamps形式 , 自定義時間格式
//@Controller 會調用視圖解析器
@RestController //會傳回字元串
public class UserController {
@RequestMapping(value = "/j3")
public String Json3() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
//使用ObjectMapper 來格式化輸出
//不使用時間戳的方法
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
Date date = new Date();
//ObjectMapper 時間解析後的預設格式為 時間戳 Timestamp
//自定義日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sdf.format(date);
String str = mapper.writeValueAsString(format);
return str;
}
}
運作結果 : 成功的輸出了時間!
也可以這樣!
方式一:
@RequestMapping("/j3")
@ResponseBody
public String json6() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Date date = new Date();
//自定義日期的格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// objectMapper,時間解析後的預設格式為: Timestamp, 時間裁
return mapper.writeValueAsString(sdf.format(date));
}
方式二:
//@Controller 會調用視圖解析器
@RestController //會傳回字元串
public class UserController {
@RequestMapping(value = "/j3")
public String Json3() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
//使用ObjectMapper 來格式化輸出
//不使用時間戳的方法
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
//自定義日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(sdf);
Date date = new Date();
//ObjectMapper 時間解析後的預設格式為 時間戳 Timestamp
return mapper.writeValueAsString(date);
}
}
抽取為工具類
如果要經常使用的話,這樣是比較麻煩的,我們可以将這些代碼封裝到一個工具類中;我們去編寫下
package com.kk.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();
//不使用時間戳的方法
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
//自定義日期格式
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
使用工具類,代碼就更加簡潔了!
@RequestMapping(value = "/j4")
public String Json4() throws JsonProcessingException {
Date date=new Date();
// return JsonUtils.getJson(date,"yyyy-MM-dd HH:mm:ss");
return JsonUtils.getJson(date);
}
2.FastJson
fastjson.jar是阿裡開發的一款專門用于Java開發的包,可以友善的實作json對象與JavaBean對象的轉換,實作JavaBean對象與json字元串的轉換,實作json對象與json字元串的轉換。實作json的轉換方法很多,最後的實作結果都是一樣的。
fastjson 的 pom依賴!
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
fastjson 三個主要的類:
- 【JSONObject 代表 json 對象 】
- JSONObject實作了Map接口, 猜想 JSONObject底層操作是由Map實作的。
- JSONObject對應json對象,通過各種形式的get()方法可以擷取json對象中的資料,也可利用諸如size(),isEmpty()等方法擷取"鍵:值"對的個數和判斷是否為空。其本質是通過實作Map接口并調用接口中的方法完成的。
- 【JSONArray 代表 json 對象數組】
- 内部是有List接口中的方法來完成操作的。
- 【JSON 代表 JSONObject和JSONArray的轉化】
- JSON類源碼分析與使用
- 仔細觀察這些方法,主要是實作json對象,json對象數組,javabean對象,json字元串之間的互相轉化。
代碼測試,我們建立一個測試 類
//@Controller 會調用視圖解析器
@RestController //會傳回字元串
public class UserController {
@RequestMapping(value = "/j5")
public String Json5() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
//使用集合
List<User> userList=new ArrayList<User>();
User user1 = new User("1号",17,"男");
User user2 = new User("1号",17,"男");
User user3 = new User("1号",17,"男");
User user4 = new User("1号",17,"男");
User user5 = new User("1号",17,"男");
User user6 = new User("1号",17,"男");
User user7 = new User("1号",17,"男");
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.add(user5);
userList.add(user6);
userList.add(user7);
String s = JSON.toJSONString(userList);
return s;
}
}
測試:
http://localhost:8080/j5
11、Ajax研究
- AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)。
- AJAX 是一種在無需重新加載整個網頁的情況下,能夠更新部分網頁的技術。
- Ajax 不是一種新的程式設計語言,而是一種用于建立更好更快以及互動性更強的Web應用程式的技術。
- 在 2005 年,Google 通過其 Google Suggest 使 AJAX 變得流行起來。Google Suggest能夠自動幫你完成搜尋單詞。
- Google Suggest 使用 AJAX 創造出動态性極強的 web 界面:當您在谷歌的搜尋框輸入關鍵字時,JavaScript 會把這些字元發送到伺服器,然後伺服器會傳回一個搜尋建議的清單。
- 就和國内百度的搜尋框一樣!
- 傳統的網頁(即不用ajax技術的網頁),想要更新内容或者送出一個表單,都需要重新加載整個網頁。
- 使用ajax技術的網頁,通過在背景伺服器進行少量的資料交換,就可以實作異步局部更新。
- 使用Ajax,使用者可以建立接近本地桌面應用的直接、高可用、更豐富、更動态的Web使用者界面。
僞造Ajax
我們可以使用前端的一個标簽來僞造一個ajax的樣子。iframe标簽
1、建立一個module :sspringmvc-06-ajax , 導入web支援!
2、編寫一個 ajax-frame.html 使用 iframe 測試,感受下效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>iframe測試體驗頁面無重新整理</title>
<script>function go(){
var url=document.getElementById("url").value;
document.getElementById("iframe1").src=url;
}</script>
</head>
<body>
<div>
<p>請輸入位址:</p>
<p>
<input type="text" id="url" value="https://blog.csdn.net/weixin_50569789?spm=1000.2115.3001.5343">
<input type="button" value="送出" onclick="go()">
</p>
</div>
<div>
<iframe id="iframe1"style="width: 100%;height: 500px;"></iframe>
</div>
</body>
</html>
3、使用IDEA開浏覽器測試一下!
利用AJAX可以做:
- 注冊時,輸入使用者名自動檢測使用者是否已經存在。
- 登陸時,提示使用者名密碼錯誤
- 删除資料行時,将行ID發送到背景,背景在資料庫中删除,資料庫删除成功後,在頁面DOM中将資料行也删除。
- …
jQuery.ajax
純JS原生實作Ajax我們不去講解這裡,直接使用jquery提供的,友善學習和使用,避免重複造輪子,有興趣的同學可以去了解下JS原生XMLHttpRequest !
Ajax的核心是XMLHttpRequest對象(XHR)。XHR為向伺服器發送請求和解析伺服器響應提供了接口。能夠以異步方式從伺服器擷取新資料。
jQuery 提供多個與 AJAX 有關的方法。
通過 jQuery AJAX 方法,您能夠使用 HTTP Get 和 HTTP Post 從遠端伺服器上請求文本、HTML、XML 或 JSON – 同時您能夠把這些外部資料直接載入網頁的被選元素中。
jQuery 不是生産者,而是大自然搬運工。
jQuery Ajax本質就是 XMLHttpRequest,對他進行了封裝,友善調用!
jQuery.ajax(...)
部分參數:
url:請求位址
type:請求方式,GET、POST(1.9.0之後用method)
headers:請求頭
data:要發送的資料
contentType:即将發送資訊至伺服器的内容編碼類型(預設: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否異步
timeout:設定請求逾時時間(毫秒)
beforeSend:發送請求前執行的函數(全局)
complete:完成之後執行的回調函數(全局)
success:成功之後執行的回調函數(全局)
error:失敗之後執行的回調函數(全局)
accepts:通過請求頭發送給伺服器,告訴伺服器目前用戶端可接受的資料類型
dataType:将伺服器端傳回的資料轉換成指定類型
"xml": 将伺服器端傳回的内容轉換成xml格式
"text": 将伺服器端傳回的内容轉換成普通文本格式
"html": 将伺服器端傳回的内容轉換成普通文本格式,在插入DOM中時,如果包含JavaScript标簽,則會嘗試去執行。
"script": 嘗試将傳回值當作JavaScript去執行,然後再将伺服器端傳回的内容轉換成普通文本格式
"json": 将伺服器端傳回的内容轉換成相應的JavaScript對象
"jsonp": JSONP 格式使用 JSONP 形式調用函數時,如 "myurl?callback=?" jQuery 将自動替換 ? 為正确的函數名,以執行回調函數
簡單案例:(前後端互動)
1、配置web.xml 和 application的配置檔案,複制上面案例的即可 【記得靜态資源過濾和注解驅動配置上】
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">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
</web-app>
application
<?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/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
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.kk.controller"/>
<mvc:annotation-driven/>
<!-- 靜态資源過濾-->
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<!-- 3.配置jsp 顯示ViewResolver視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
2、編寫一個AjaxController
package com.kk.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
public class AjaxController {
@RequestMapping("/t1")
public String test(){
return "hello";
}
@RequestMapping("a1") //發起一個請求
public void a1(String name, HttpServletResponse response) throws IOException {
System.out.println("a1:param=>"+name);
if ("kk".equals(name)){
response.getWriter().print("true");
}else{
response.getWriter().print("false");
}
}
}
3、導入jquery , 可以使用線上的CDN , 也可以下載下傳導入
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script>
4、編寫index.jsp測試
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
<script>function a() {
$.post({
url:"${pageContext.request.contextPath}/a1",
data:{"name":$("#username").val()}, //取到輸入框的值
success:function (data,status) {
console.log("data="+data);
console.log("status="+status);
},error:function () {
}
})
}</script>
</head>
<body>
<%-- 失去焦點的時候,發起一個請求(攜帶資訊)到背景--%>
使用者名:<input type="text" id="username" onblur="a()">
</body>
</html>
5、啟動tomcat測試!打開浏覽器的控制台,當我們滑鼠離開輸入框的時候,可以看到發出了一個ajax的請求!是背景傳回給我們的結果!測試成功!
Springmvc實作
實體類User
package com.kk.pojo;
public class User {
private String name;
private int age;
private String sex;
public User() {
}
public User(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
我們來擷取一個集合對象,展示到前端頁面
@RequestMapping("a2")
public List<User> a2(){
List<User> userList = new ArrayList<User>();
//添加資料
userList.add(new User("Java",1,"男"));
userList.add(new User("Linus",1,"男"));
userList.add(new User("Mysql",1,"男"));
return userList;
}
前端頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
<script>
$(function () {
$("#btn").click(function(){
$.post({
url:"${pageContext.request.contextPath}/a2",
success:function (data) {
console.log(data)
var html=""
for (let i = 0; i < data.length; i++) {
html+="<tr>"+
"<td>"+data[i].name+"</td>"+
"<td>"+data[i].age+"</td>"+
"<td>"+data[i].sex+"</td>"+
"</tr>"
}
$("#content").html(html);
}
})
})
})
</script>
</head>
<body>
<input type="button" value="加載資料" id="btn">
<table>
<tr>
<td>姓名</td>
<td>年齡</td>
<td>性别</td>
</tr>
<tbody id="content">
<%-- 資料: 從背景擷取--%>
</tbody>
</table>
</body>
</html>
成功實作了資料回顯!
Ajax驗證使用者名案例
AjaxController
@RequestMapping("/a3")
public String a3(String name,String pwd) {
String msg="";
if (name != null) {
if ("admin".equals(name)) {
msg="OK";
}else {
msg="使用者名有誤!";
}
}
if (pwd != null) {
if ("123456".equals(pwd)) {
msg="OK";
}else {
msg="密碼有誤!";
}
}
return msg;
}
需要在application配置json亂碼問題
<?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/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
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--自動掃描指定的包 下面所有注解類交給IOC容器管理-->
<context:component-scan base-package="com.kk.controller"/>
<mvc:annotation-driven/>
<!--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>
<!-- 靜态資源過濾-->
<mvc:default-servlet-handler/>
<!-- 3.配置jsp 顯示ViewResolver視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
login.jsp頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
<script>
function a1() {
$.post({
url:"${pageContext.request.contextPath}/a3",
data:{"name":$("#name").val()},//從前端中擷取資料
success:function (data){
if (data.toString()==='OK'){
$("#userInfo").css("color","green");
}else{
$("#userInfo").css("color","red");
}
$("#userInfo").html(data); //将資料回報到前端頁面去
// console.log(data.toString()); //轉換為字元串
}
})
}
function a2() {
$.post({
url:"${pageContext.request.contextPath}/a3",
data:{"pwd":$("#pwd").val()},//從前端中擷取資料
success:function (data){
if (data.toString()==='OK'){
$("#pwdInfo").css("color","green");
}else{
$("#pwdInfo").css("color","red");
}
$("#pwdInfo").html(data); //将資料回報到前端頁面去
// console.log(data.toString()); //轉換為字元串
}
})
}
</script>
</head>
<body>
<p>
使用者名:<input type="text" id="name" οnblur="a1()">
<span id="userInfo"></span>
</p>
<p>
密碼:<input type="text" id="pwd" οnblur="a2()">
<span id="pwdInfo"></span>
</p>
</body>
</html>
動态請求響應,局部重新整理,就是如此!
案例擷取baidu接口
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>JSONP百度搜尋</title>
<style>
#q{
width: 500px;
height: 30px;
border:1px solid #ddd;
line-height: 30px;
display: block;
margin: 0 auto;
padding: 0 10px;
font-size: 14px;
}
#ul{
width: 520px;
list-style: none;
margin: 0 auto;
padding: 0;
border:1px solid #ddd;
margin-top: -1px;
display: none;
}
#ul li{
line-height: 30px;
padding: 0 10px;
}
#ul li:hover{
background-color: #f60;
color: #fff;
}
</style>
<script>
// 2.步驟二
// 定義demo函數 (分析接口、資料)
function demo(data){
var Ul = document.getElementById('ul');
var html = '';
// 如果搜尋資料存在 把内容添加進去
if (data.s.length) {
// 隐藏掉的ul顯示出來
Ul.style.display = 'block';
// 搜尋到的資料循環追加到li裡
for(var i = 0;i<data.s.length;i++){
html += '<li>'+data.s[i]+'</li>';
}
// 循環的li寫入ul
Ul.innerHTML = html;
}
}
// 1.步驟一
window.onload = function(){
// 擷取輸入框和ul
var Q = document.getElementById('q');
var Ul = document.getElementById('ul');
// 事件滑鼠擡起時候
Q.onkeyup = function(){
// 如果輸入框不等于空
if (this.value != '') {
// ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆JSONPz重點☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
// 建立标簽
var script = document.createElement('script');
//給定要跨域的位址 指派給src
//這裡是要請求的跨域的位址 我寫的是百度搜尋的跨域位址
script.src ='https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+this.value+'&cb=demo';
// 将組合好的帶src的script标簽追加到body裡
document.body.appendChild(script);
}
}
}
</script>
</head>
<body>
<input type="text" id="q" />
<ul id="ul">
</ul>
</body>
</html>
攔截器
概述
SpringMVC的處理器攔截器類似于Servlet開發中的過濾器Filter,用于對處理器進行預處理和後處理。開發者可以自己定義一些攔截器來實作特定的功能。
**過濾器與攔截器的差別:**攔截器是AOP思想的具體應用。
過濾器
- servlet規範中的一部分,任何java web工程都可以使用
- 在url-pattern中配置了/*之後,可以對所有要通路的資源進行攔截
攔截器
- 攔截器是SpringMVC架構自己的,隻有使用了SpringMVC架構的工程才能使用
- 攔截器隻會攔截通路的控制器方法, 如果通路的是jsp/html/css/image/js是不會進行攔截的
自定義攔截器
那如何實作攔截器呢?
想要自定義攔截器,必須實作 HandlerInterceptor 接口。
1、建立一個Moudule , springmvc-07-Interceptor , 添加web支援
2、配置web.xml 和 springmvc-servlet.xml 檔案
3、編寫一個攔截器
package com.kk.config;
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 {
//return true 執行下一個攔截器 放行
//return false 不執行下一個攔截器
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("======================處理前========================");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("======================處理後========================");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("=====================清理=========================");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
//這裡寫完之後 需要到application.xml中配置
4、在springmvc(或者application.xml)的配置檔案中配置攔截器
<!-- 攔截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 包括這個請求下面的所有請求 /admin/ada/daad-->
<mvc:mapping path="/**"/>
<bean class="com.kk.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
5、編寫一個Controller,接收請求
//測試攔截器的控制器
@Controller
public class InterceptorController {
@RequestMapping("/interceptor")
@ResponseBody
public String testFunction() {
System.out.println("控制器中的方法執行了");
return "hello";
}
}
6、前端 index.jsp
<a href="${pageContext.request.contextPath}/interceptor">攔截器測試</a>
7、啟動tomcat 測試一下!
使用攔截器驗證使用者是否登入 (認證使用者)
實作思路
1、有一個登陸頁面,需要寫一個controller通路頁面。
2、登陸頁面有一送出表單的動作。需要在controller中處理。判斷使用者名密碼是否正确。如果正确,向session中寫入使用者資訊。傳回登陸成功。
3、攔截使用者請求,判斷使用者是否登陸。如果使用者已經登陸。放行, 如果使用者未登陸,跳轉到登陸頁面
測試:
1、編寫一個登陸頁面 在web的web-inf目錄下建立jsp檔案夾,然後建立login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 在web-inf下的所有頁面或者資源,隻能通過controller或者servlet進行通路--%>
<h1>登陸頁面</h1>
<form action="${pageContext.request.contextPath}/user/login" method="post">
使用者名: <input type="text" name="username"/>
密碼: <input type="password" name="password"/>
<input type="submit" value="登陸">
</form>
</body>
</html>
2、編寫一個Controller處理請求
package com.kk.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class LoginController {
@RequestMapping("/main")
public String main(){
return "main";
}
@RequestMapping("/goLogin")
public String login(){
return "login"; //點選登入之後 跳轉到登陸頁面
}
@RequestMapping("/login")
public String login(HttpSession session, String username, String password, Model model){
System.out.println("login=>"+username);
//把使用者的資訊存在session中
session.setAttribute("userLoginInfo",username);
model.addAttribute("username",username);
return "main"; //點選送出登陸之後 跳轉到首頁
}
@RequestMapping("/goOut")
public String goOut(HttpSession session){
session.removeAttribute("userLoginInfo");
return "main"; //點選登出之後 跳轉到首頁
}
}
3、編寫一個登入成功後跳轉到首頁面 在web的web-inf目錄下建立jsp檔案夾下建立main.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>首頁</h1>
<%-- 使用model将資料顯示給前端--%>
<span>${username}</span>
<p>
<a href="${pageContext.request.contextPath}/user/goOut">登出</a>
</p>
</body>
</html>
5、編寫使用者登入攔截器
package com.kk.config;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
// 放行的判斷:判斷什麼情況下登陸了
//在登陸頁面 也放行
if (request.getRequestURI().contains("Login")){
return true;
}
//說明我在送出登陸
if (request.getRequestURI().contains("login")){
return true;
}
//第一次登陸 也是沒有session的
if (session.getAttribute("userLoginInfo")!=null){
return true;
}
//判斷什麼情況下沒有登陸
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);//重定向
return false;
}
}
6、在Springmvc(application.xml)的配置檔案中注冊攔截器
<!-- 運用了橫切aop思想-->
<!-- 攔截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 包括這個請求下面的所有請求 /admin/ada/daad-->
<mvc:mapping path="/user/**"/>
<bean class="com.kk.config.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
7、再次重新開機Tomcat測試!
OK,測試登入攔截功能無誤.
檔案上傳和下載下傳
準備工作
檔案上傳是項目開發中最常見的功能之一 ,springMVC 可以很好的支援檔案上傳,但是SpringMVC上下文中預設沒有裝配MultipartResolver,是以預設情況下其不能處理檔案上傳工作。如果想使用Spring的檔案上傳功能,則需要在上下文中配置MultipartResolver。
前端表單要求:為了能上傳檔案,必須将表單的method設定為POST,并将enctype設定為multipart/form-data。隻有在這樣的情況下,浏覽器才會把使用者選擇的檔案以二進制資料發送給伺服器;
對表單中的 enctype 屬性做個詳細的說明:
- application/x-www=form-urlencoded:預設方式,隻處理表單域中的 value 屬性值,采用這種編碼方式的表單會将表單域中的值處理成 URL 編碼方式。
- multipart/form-data:這種編碼方式會以二進制流的方式來處理表單資料,這種編碼方式會把檔案域指定檔案的内容也封裝到請求參數中,不會對字元編碼。
- text/plain:除了把空格轉換為 “+” 号外,其他字元都不做編碼處理,這種方式适用直接通過表單發送郵件。
<form action="" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit">
</form>
一旦設定了enctype為multipart/form-data,浏覽器即會采用二進制流的方式來處理表單資料,而對于檔案上傳的處理則涉及在伺服器端解析原始的HTTP響應。在2003年,Apache Software Foundation釋出了開源的Commons FileUpload元件,其很快成為Servlet/JSP程式員上傳檔案的最佳選擇。
- Servlet3.0規範已經提供方法來處理檔案上傳,但這種上傳需要在Servlet中完成。
- 而Spring MVC則提供了更簡單的封裝。
- Spring MVC為檔案上傳提供了直接的支援,這種支援是用即插即用的MultipartResolver實作的。
- Spring MVC使用Apache Commons FileUpload技術實作了一個MultipartResolver實作類:
- CommonsMultipartResolver。是以,SpringMVC的檔案上傳還需要依賴Apache Commons FileUpload的元件。
檔案上傳
1、導入檔案上傳的jar包,commons-fileupload , Maven會自動幫我們導入他的依賴包 commons-io包;
<dependencies><!--檔案上傳 使用最高版本-->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--servlet-api導入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
2、配置bean:multipartResolver
【注意!!!這個bena的id必須為:multipartResolver , 否則上傳檔案會報400的錯誤!在這裡栽過坑,教訓!】
CommonsMultipartFile 的 常用方法:
- String getOriginalFilename():擷取上傳檔案的原名
- InputStream getInputStream():擷取檔案流
- void transferTo(File dest):将上傳檔案儲存到一個目錄檔案中
測試
3.編寫前端頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit">
</form>
</body>
</html>
4、Controller
方式一:
package com.kk.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@RestController
public class FileController {
//@RequestParam("file") 将name=file控件得到的檔案封裝成CommonsMultipartFile 對象
//批量上傳CommonsMultipartFile則為數組即可
@RequestMapping("/upload")
public String fileUpload(@RequestParam("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";
}
}
方式二:
采用file.Transto 來儲存上傳的檔案
1、編寫Controller
/*
* 采用file.Transto 來儲存上傳的檔案
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("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";
}
2、前端表單送出位址修改
3、通路送出測試,OK!
檔案下載下傳
檔案下載下傳步驟:
1、設定 response 響應頭
2、讀取檔案 – InputStream
3、寫出檔案 – OutputStream
4、執行操作
5、關閉流 (先開後關)
代碼實作:
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
//要下載下傳的圖檔位址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "img.jpg";
//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;
}
前端
<a href="${pageContext.request.contextPath}/static/img.png">點選下載下傳</a>
測試,檔案下載下傳OK
完結!!!
) 将name=file控件得到的檔案封裝成CommonsMultipartFile 對象
//批量上傳CommonsMultipartFile則為數組即可
@RequestMapping("/upload")
public String fileUpload(@RequestParam(“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";
}
}
#### 方式二:
**采用file.Transto 來儲存上傳的檔案**
1、編寫Controller
```java
/*
* 采用file.Transto 來儲存上傳的檔案
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("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";
}
2、前端表單送出位址修改
3、通路送出測試,OK!
檔案下載下傳
檔案下載下傳步驟:
1、設定 response 響應頭
2、讀取檔案 – InputStream
3、寫出檔案 – OutputStream
4、執行操作
5、關閉流 (先開後關)
代碼實作:
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
//要下載下傳的圖檔位址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "img.jpg";
//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;
}
前端
<a href="${pageContext.request.contextPath}/static/img.png">點選下載下傳</a>