1.spring mvc
Spring MVC是Spring Framework的一部分,是基於Java實現MVC的輕量級Web框架。
檢視官方文件:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web
1.1.三層結構
B/S架構系統標準的三層架構包括表現層、業務層和持久層,每一層各司其職, 接下來我們就說說每層都負責哪些方面。
表現層
也就是我們常說的web層。它負責接收客戶端請求,向客戶端響應結果,通常客戶端使用http協議請求web 層,web 需要接收 http 請求,完成 http 響應。
-
表現層又包括展示層和控制層:控制層負責接收請求,展示層負責結果的展示。
-
表現層依賴業務層,接收到客戶端請求一般會呼叫業務層進行業務處理,並將處理結果響應給客戶端。
-
表現層的設計一般都使用 MVC 模型。(MVC 是表現層的設計模型,和其他層沒有關係)
業務層:
也就是我們常說的 service 層。它負責業務邏輯處理,和我們開發專案的需求息息相關。
-
web 層依賴業務層,但是業務層不依賴 web 層。
-
業務層在業務處理時可能會依賴持久層,如果要對資料持久化需要保證事務一致性。(也就是我們說的,事務應該放到業務層來控制)
持久層:
也就是我們是常說的 dao 層。負責資料持久化,包括資料層即資料庫和資料訪問層,資料庫是對資料進行持久化的載體,資料訪問層是業務層和持久層互動的介面,業務層需要通過資料訪問層將資料持久化到資料庫中。通俗的講,持久層就是和資料庫互動,對資料庫表進行曾刪改查的。
通過分層更好的實現了各個部分的職責,在每一層將再細化出不同的框架,分別解決各層關注的問題。三層架構與SSM的關係示意圖如下,其中SpringMVC屬於表現層框架,MyBatis屬於持久層框架,而Spring不屬於任何一層,是用來整合其它框架的。
1.2.mvc 模型
MVC全名是Model View Controller,是模型(model)-檢視(view)-控制器(controller)的縮寫,是一種用於設計建立 Web 應用程式表現層的模式。MVC 中每個部分各司其職:
Model(模型)
指的就是我們的資料模型,一般情況下用於封裝資料。
View(檢視)
指的就是我們的 jsp 或者 html等頁面,一般用於展示資料的,其是依據模型資料建立的。
Controller(控制器)
是應用程式中處理使用者互動的部分,用來處理程式邏輯的。例如引數校驗等。
1.3.Spring MVC
1.3.1.特點:
-
清晰的角色劃分
前端控制器(DispatcherServlet)
請求到處理器對映(HandlerMapping)
處理器介面卡(HandlerAdapter)
檢視解析器(ViewResolver)
處理器或頁面控制器(Controller)
驗證器( Validator)
命令物件(Command 請求引數繫結到的物件就叫命令物件)
表單物件(Form Object 提供給表單展示和提交到的物件就叫表單物件)。
-
分工明確,而且擴充套件點相當靈活,可以很容易擴充套件,雖然幾乎不需要。
-
由於命令物件就是一個 POJO,無需繼承框架特定 API,可以使用命令物件直接作為業務物件。
-
和 Spring 其他框架無縫整合,是其它 Web 框架所不具備的。
-
可適配,通過 HandlerAdapter 可以支援任意的類作為處理器。
-
可定製性,HandlerMapping、ViewResolver 等能夠非常簡單的定製。
-
功能強大的資料驗證、格式化、繫結機制。
-
利用 Spring 提供的 Mock 物件能夠非常簡單的進行 Web 層單元測試。
-
本地化、主題的解析的支援,使我們更容易進行國際化和主題的切換。
-
強大的 JSP 標籤庫,使 JSP 編寫更容易。
-
還有比如RESTful風格的支援、簡單的檔案上傳、約定大於配置的契約式程式設計支援、基於註解的零配置支援,資料驗證、格式化、本地化、主題等等。
-
用的人多。
1.3.2.執行流程
1.4.SpringMVC 和 Struts2
共同點:
-
它們都是表現層框架,都是基於 MVC 模型編寫的。
-
它們的底層都離不開原始 ServletAPI。
-
它們處理請求的機制都是一個核心控制器。
區別:
-
Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter
-
Spring MVC 是基於方法設計的,而 Struts2 是基於類,Struts2 每次執行都會建立一個動作類。所以 Spring MVC 會稍微比 Struts2 快些。
-
Spring MVC 使用更加簡潔,同時還支援 JSR303, 處理 ajax 的請求更方便(JSR303 是一套 JavaBean 引數校驗的標準,它定義了很多常用的校驗註解,我們可以直接將這些註解加在我們 JavaBean 的屬性上面,就可以在需要校驗的時候進行校驗了。)
-
Struts2 的 OGNL 表示式使頁面的開發效率相比 Spring MVC 更高些,但執行效率並沒有比 JSTL 提升,尤其是 struts2 的表單標籤,遠沒有 html 執行效率高
2.spring mvc入門demo
2.1.配置版
建立model,新增目錄java,resources.
實現步驟其實非常的簡單:
- 新建一個web專案
- 匯入相關jar包
- 編寫web.xml , 註冊DispatcherServlet
- 編寫springmvc配置檔案
- 接下來就是去建立對應的控制類 , controller
- 最後完善前端檢視和controller之間的對應
- 測試執行除錯.
2.1.1.新增依賴
<dependencies>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-mvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--servletAPI-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
2.1.2.配置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">
<!--1.註冊DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--關聯一個springmvc的配置檔案:【servlet-name】-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--啟動級別-1-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的請求;(不包括.jsp)-->
<!--/* 匹配所有的請求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.1.3.新增資原始檔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">
<!--新增 處理對映器-->
<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/page/"/>
<!--字尾-->
<property name="suffix" value=".jsp"/>
</bean>
<!--將自己的類交給SpringIOC容器,註冊bean-->
<!--Handler-->
<bean id="/hello" class="com.wyl.HelloController"/>
</beans>
使用springMVC必須配置的三大件:
處理器對映器、處理器介面卡、檢視解析器
通常,我們只需要手動配置檢視解析器,而處理器對映器和處理器介面卡只需要開啟註解驅動即可,而省去了大段的xml配置
2.1.4.新增軟體包 com.wyl.controller,新增controller
package com.wyl.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @建立人 王延領
* @建立時間 2021/10/15
* 描述
**/
public class HelloController implements Controller{
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//ModelAndView模型和檢視
ModelAndView mv = new ModelAndView();
//封裝物件,放在ModeAndView
mv.addObject("msg","王延領學習java");
//封裝要跳轉的檢視,放在ModelAndView中
mv.setViewName("hello");
return mv;
}
}
2.1.5. 新增對映
<!--將自己的類交給SpringIOC容器,註冊bean-->
<!--Handler-->
<bean id="/hello" class="com.wyl.HelloController"/>
2.1.6.新增頁面
2.1.7.tomcat執行
2.2.註解版
2.2.1.新增依賴
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-mvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--servletAPI-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
2.2.1.配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--不要web-app,不然model 返回失效-->
<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>
<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 >
不會匹配到.jsp, 只針對我們編寫的請求;即:.jsp 不會進入spring的 DispatcherServlet類 。
< url-pattern > /* </ url-pattern >
會匹配 *.jsp,會出現返回 jsp檢視 時再次進入spring的DispatcherServlet 類,導致找不到對應的controller所以報404錯-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.2.3.新增資原始檔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.wyl.controller"/>
<!-- 讓Spring MVC不處理靜態資源 -->
<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>
2.2.4.新增軟體包 com.wyl.controller,新增controller
package com.wyl.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @建立人 王延領
* @建立時間 2021/10/18
* 描述
**/
@Controller
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/sayHello")
public String hello(Model model) {
//會被檢視解析器處理
return "hello";
}
}
2.1.5.新增頁面
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/15
Time: 23:55
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
成功!!!
</body>
</html>
3.控制器
3.1.@Controller
-
@Controller註解型別用於宣告Spring類的例項是一個控制器;
-
Spring可以使用掃描機制來找到應用程式中所有基於註解的控制器類,為了保證Spring能找到你的控制器,需要在配置檔案中宣告元件掃描。
<!-- 自動掃描指定的包,下面所有註解類交給IOC容器管理 --> <context:component-scan base-package="com.wyl.controller"/>
//@Controller註解的類會自動新增到Spring上下文中 @Controller public class ControllerTest2{ //對映訪問路徑 @RequestMapping("/t2") public String index(Model model){ //Spring MVC會自動例項化一個Model物件用於向檢視中傳值 model.addAttribute("msg", "ControllerTest2"); //返回檢視位置 return "test"; } }
3.2.@RequestMapping
3.2.1.RequestMapping註解:
* 作用:
* 用於建立請求URL和處理請求方法之間的對應關係
* 它可以作用在方法、類上
* 作用來類上:作用在類上時,類上的路徑作為一級目錄
* 在訪問方法時需要加類上的路徑
* 作用在方法上:指定這個方法要攔截處理哪個URL請求
* 屬性:
* value:與path屬性的作用是相同的,當只有value一個屬性時,屬性可以省略,直接寫屬性值
* path:與value屬性作用一致,用於指定請求的URL
* method:用於指定請求的方式,比如POST、GET等使用RequestMethod列舉
* params:用於指定限制請求引數的條件,它支援簡單的表示式
* 要求請求引數的key和value必須和配置的一模一樣
* headers:用於指定限制請求訊息頭的條件
@Controller
@RequestMapping("/User")
public class RequestMappingDemoController {
@RequestMapping("SetView")
public String SetView(){
System.out.println("Hello SpringMvc");
//返回邏輯檢視名
return "success";
}
//類上加了@RequestMapping註解後,此方法攔截的URL變成了:user/testRequestMapping
@RequestMapping("/testRequestMapping")
public String testRequestMapping(){
System.out.println("測試RequestMapping註解。。");
//返回邏輯檢視名
return "success";
}
//指定此方法只能由POST請求訪問
@RequestMapping(path = {"/testRequestMappingMethod"},method = {RequestMethod.POST})
public String testRequestMappingMethod(){
System.out.println("測試RequestMapping註解的method屬性。。");
//返回邏輯檢視名
return "success";
}
//指定此方法必須帶有name屬性,且屬性值必須為admin
//http://localhost:8080/User/testRequestMappingParams?name=admin
@RequestMapping(path = {"/testRequestMappingParams"},params = {"name=admin"})
public String testRequestMappingParams(){
System.out.println("測試RequestMapping註解的params屬性。。");
//返回邏輯檢視名
return "success";
}
//指定請求頭中必須包含accept屬性
@RequestMapping(path = {"/testRequestMappingHeaders"},headers = {"accept"})
public String testRequestMappingHeaders(){
System.out.println("測試RequestMapping註解的headers屬性。。");
//返回邏輯檢視名
return "success";
}
}
3.2.2.RestFul風格
//對映訪問路徑
@RequestMapping("/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable int p2, Model model){
int result = p1+p2;
//Spring MVC會自動例項化一個Model物件用於向檢視中傳值
model.addAttribute("msg", "結果:"+result);
//返回檢視位置
return "test";
}
-
REST(英文:Representational State Transfer,簡稱REST)描述了一個架構樣式的網路系統,比如 web 應用程式。它首次出現在 2000 年 Roy Fielding 的博士論文中,他是 HTTP 規範的主要編寫者之一。在目前主流的三種Web服務互動方案中,REST相比於SOAP(Simple Object Access protocol,簡單物件訪問協議)以及XML-RPC更加簡單明瞭,無論是對URL的處理還是對Payload的編碼,REST都傾向於用更加簡單輕量的方法設計和實現。值得注意的是REST並沒有一個明確的標準,而更像是一種設計的風格。
-
它本身並沒有什麼實用性,其核心價值在於如何設計出符合REST風格的網路介面。
-
restful的優點 :
- 它結構清晰、符合標準、易於理解、擴充套件方便,所以正得到越來越多網站的採用。
-
restful的特性:
-
資源(Resources):
- 網路上的一個實體,或者說是網路上的一個具體資訊。 它可以是一段文字、一張圖片、一首歌曲、一種服務,總之就是一個具體的存在。可以用一個URI(統一資源定位符)指向它,每種資源對應一個特定的 URI 。要 獲取這個資源,訪問它的URI就可以,因此 URI 即為每一個資源的獨一無二的識別符。
-
表現層(Representation):
- 把資源具體呈現出來的形式,叫做它的表現層 (Representation)。 比如,文字可以用 txt 格式表現,也可以用 HTML 格式、XML 格式、JSON 格式表現,甚至可以採用二進位制格式。
-
狀態轉化(State Transfer):
- 每 發出一個請求,就代表了客戶端和伺服器的一次互動過程。 HTTP協議,是一個無狀態協議,即所有的狀態都儲存在伺服器端。因此,如果客戶端想要操作伺服器,必須通過某種手段,讓伺服器端發生“狀態轉化”(State Transfer)。而這種轉化是建立在表現層之上的,所以就是 “表現層狀態轉化”。具體說,就是 HTTP 協議裡面,四個表示操作方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操作:GET 用來獲取資源,POST 用來新建資源,PUT 用來更新資源,DELETE 用來刪除資源。
-
3.2.3.組合註解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping 是一個組合註解@RequestMapping(method =RequestMethod.GET) 的一個快捷方式
//原來的:http://localhost:8080/add?a=1&b=2
//RestFul風格:http://localhost:8080/add/a/b
// @RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
@GetMapping("/add/{a}/{b}")
public String test1(@PathVariable int a, @PathVariable int b, Model model) {//@PathVariable路徑變數
int res = a + b;
model.addAttribute("msg", "結果為:" + res);
return "test";
}
// @RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.Post)
@PostMapping("/add/{a}/{b}")
public String test2(@PathVariable int a, @PathVariable int b, Model model) {//@PathVariable路徑變數
int res = a + b;
model.addAttribute("msg", "結果為:" + res);
return "test";
}
3.3.結果跳轉
3.3.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 ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一個模型檢視物件
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ModelAndView 返回!!!");
mv.setViewName("test");
return mv;
}
}
3.3.2.ServletAPI
通過設定ServletAPI , 不需要檢視解析器 .
1、通過HttpServletResponse進行輸出
2、通過HttpServletResponse實現重定向
3、通過HttpServletResponse實現轉發
@Controller
public class ResultGo {
@RequestMapping("/result/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.getWriter().println("Hello,Spring BY servlet API");
}
@RequestMapping("/result/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.sendRedirect("/index.jsp");
}
@RequestMapping("/result/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//轉發
req.setAttribute("msg","/result/t3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}
}
3.3.3.SpringMVC
通過SpringMVC來實現轉發和重定向 - 無需檢視解析器;
測試前,需要將檢視解析器註釋掉
@Controller
public class ResultSpringMVC {
@RequestMapping("/rsm/t1")
public String test1(){
//轉發
return "/index.jsp";
}
@RequestMapping("/rsm/t2")
public String test2(){
//轉發二
return "forward:/index.jsp";
}
@RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
通過SpringMVC來實現轉發和重定向 - 有檢視解析器;
重定向 , 不需要檢視解析器 , 本質就是重新請求一個新地方嘛 , 所以注意路徑問題.
可以重定向到另外一個請求實現 .
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//轉發
return "test";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:hello.do";
}
}
3.4.處理提交資料
3.4.1.提交的域名稱和處理方法的引數名一致
提交資料 : http://localhost:8080/hello?name=wyl
處理方法 :
@RequestMapping("/hello")
public String hello(String name){
System.out.println(name);
return "test";
}
3.4.2.提交的域名稱和處理方法的引數名不一致
提交資料 : http://localhost:8080/hello?username=wyl
處理方法 :
/**
* 請求引數繫結
* 請求的引數中如果有username屬性的話,
* SpringMVC會自動將引數傳入與方法引數列表對應的入參中
* @return
*/
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name){
System.out.println(name);
return "test";
}
3.4.3.提交的是一個物件
要求提交的表單域和物件的屬性名一致 , 引數使用物件即可
1、實體類
public class User {
private int id;
private String name;
private int age;
//構造
//get/set
//tostring()
}
2、提交資料 : http://localhost:8080/mvc04/user?name=wyl&id=1&age=18
3、處理方法
/**
*1、接收到的前端使用者傳遞引數,判斷引數的名字,假設名字直接在方法上,可以直接使用
*2、假設傳遞的是一個物件user,就會匹配user物件的欄位名;如果欄位一致則OK,否則匹配不到
*/
@RequestMapping("/user")
public String user(User user){
System.out.println(user);
return "hello";
}
3.3.4.獲取原生ServletAPI物件
提交資料 : http://localhost:8080/hello?username=wyl&password=123456
處理方法
/**
* 獲取原生ServletAPI物件
* 需要哪個物件,在方法入參處定義就好了
* @param request
* @param response
* @return
*/
@RequestMapping("/hello")
public String hello(HttpServletRequest request, HttpServletResponse response){
System.out.println("獲取原生ServletAPI物件。。。");
System.out.println("request:"+request);
System.out.println("從request物件中獲取的使用者名稱:"+request.getParameter("username"));
System.out.println("從request物件中獲取的密碼:"+request.getParameter("password"));
System.out.println("response:"+response);
System.out.println("session:"+request.getSession());
System.out.println("application:"+request.getSession().getServletContext());
//返回邏輯檢視名
return "success";
}
3.5.返回結果
3.5.1.ModelAndView
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一個模型檢視物件
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ModelAndView");
mv.setViewName("test");
return mv;
}
}
3.5.2.ModelMap
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
//封裝要顯示到檢視中的資料
//相當於req.setAttribute("name",name);
model.addAttribute("name",name);
System.out.println(name);
return "hello";
}
3.5.3.Model
@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){
//封裝要顯示到檢視中的資料
//相當於req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}
Model 只有寥寥幾個方法只適合用於儲存資料,簡化了新手對於Model物件的操作和理解;
ModelMap 繼承了 LinkedMap ,除了實現了自身的一些方法,同樣的繼承 LinkedMap 的方法和特性;
ModelAndView 可以在儲存資料的同時,可以進行設定返回的邏輯檢視,進行控制展示層的跳轉。
4.異常處理
4.1.異常處理的思路
系統中異常包括兩類: 預期異常和執行時異常 RuntimeException,前者通過捕獲異常從而獲取異常資訊,後者主要通過規範程式碼開發、測試通過手段減少執行時異常的發生。
系統的dao、service、controller 出現都通過throws Exception 向上丟擲,最後由springmvc 前端控制器交由異常處理器進行異常處理,如下圖:
4.2.編寫異常類和錯誤頁面
/**
* 自定義異常
*/
public class CustomException extends Exception {
private String message;
public CustomException(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>執行失敗</title>
</head>
<body>
執行失敗!
${message }
</body>
</html>
4.3.自定義異常處理器
/**
* 自定義異常處理器
*/
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex
) {
ex.printStackTrace();
CustomException customException = null;
//如果丟擲的是系統自定義異常則直接轉換
if (ex instanceof CustomException) {
customException = (CustomException) ex;
} else {
//如果丟擲的不是系統自定義異常則重新構造一個系統錯誤異常。
customException = new CustomException("系統錯誤,請與系統管理 員聯絡!");
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", customException.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}
4.4.
<!-- 配置自定義異常處理器 -->
<bean id="handlerExceptionResolver"
class="com.wyl.exception.CustomExceptionResolver" />
5.json處理
ajax我經常用到,傳的資料是json資料,json資料又有物件,陣列。所有總結下springmvc獲取前端傳來的json資料方式
5.1.Controller接受JSON資料
作用:
@ResponseBody註解用於將Controller的方法返回的物件,通過springmvc提供的HttpMessageConverter介面轉換為指定格式的資料如:json,xml等,通過Response響應給客戶端。
本例子應用:
@ResponseBody註解實現將Controller方法返回java物件轉換為json響應給客戶端。
5.1.1.以RequestParam接收
前端傳來的是json資料不多時:[id:id],可以直接用@RequestParam來獲取值
@Autowired
private AccomodationService accomodationService;
@RequestMapping(value = "/update")
@ResponseBody
public String updateAttr(@RequestParam ("id") int id) {
int res=accomodationService.deleteData(id);
return "success";
}
5.1.2.以實體類方式接收
前端傳來的是一個json物件時:{【id,name】},可以用實體類直接進行自動繫結
@Autowired
private AccomodationService accomodationService;
@RequestMapping(value = "/add")
@ResponseBody
public String addObj(@RequestBody Accomodation accomodation) {
this.accomodationService.insert(accomodation);
return "success";
}
5.1.3.以Map接收
前端傳來的是一個json物件時{【id,name】},可以用Map來獲取
@Autowired
private AccomodationService accomodationService;
@RequestMapping(value = "/update")
@ResponseBody
public String updateAttr(@RequestBody Map<String, String> map) {
if(map.containsKey("id"){
Integer id = Integer.parseInt(map.get("id"));
}
if(map.containsKey("name"){
String objname = map.get("name").toString();
}
// 操作 ...
return "success";
}
5.1.4.以List接收
當前端傳來這樣一個json陣列[{id,name},{id,name},{id,name},...]時,用List
@Autowired
private AccomodationService accomodationService;
@RequestMapping(value = "/update")
@ResponseBody
//引數前面必須又@RequestBody
public String updateAttr(@RequestBody List<Accomodation> list) {
for(Accomodation accomodation:list){
System.out.println(accomodation.toString());
}
return "success";
}
ajax請求
var testList=[];
var user={};
user.id=1;
user.name='jack';
testList.push(user);
var user2={};
user2.id=2;
user2.name='tom';
testList.push(user2);
$.ajax({
// headers必須新增,否則會報415錯誤
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
type: 'POST',
dataType: "json", //表示返回值型別,不必須
data: JSON.stringify(testList),
url: '/test/postList',
success: function(){
alert('success');
}
});
需要注意點:1、引數是陣列型別
2、傳入data時,轉換 JSON.stringify(testList)
3、必須有headers:
{ 'Accept': 'application/json',
'Content-Type': 'application/json'
}
5.2.Controller返回JSON資料
5.2.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.9.8</version>
</dependency>
Controller
這裡我們需要兩個新東西,一個是@ResponseBody,一個是ObjectMapper物件,我們看下具體的用法
public class UserController {
@RequestMapping("/json1")
@ResponseBody
public String json1() throws JsonProcessingException {
//建立一個jackson的物件對映器,用來解析資料
ObjectMapper mapper = new ObjectMapper();
//建立一個物件
User user = new User("wyl", 3, "男");
//將我們的物件解析成為json格式
String str = mapper.writeValueAsString(user);
//由於@ResponseBody註解,這裡會將str轉成json格式返回;十分方便
return str;
}
}
在類上直接使用 @RestController ,這樣子,裡面所有的方法都只會返回 json 字串了,不用再每一個都新增@ResponseBody !我們在前後端分離開發中,一般都使用 @RestController ,十分便捷!
@RestController
public class UserController {
//produces:指定響應體返回型別和編碼
@RequestMapping(value = "/json1")
public String json1() throws JsonProcessingException {
//建立一個jackson的物件對映器,用來解析資料
ObjectMapper mapper = new ObjectMapper();
//建立一個物件
User user = new User("wyl", 3, "男");
//將我們的物件解析成為json格式
String str = mapper.writeValueAsString(user);
//由於@ResponseBody註解,這裡會將str轉成json格式返回;十分方便
return str;
}
}
抽取為工具類
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();
//ps:Jackson 預設是會把時間轉成timestamps形式(取消timestamps形式 , 自定義時間格式)
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;
}
}
demo
@RequestMapping("/jsonUnit")
public String json5() throws JsonProcessingException {
Date date = new Date();
String json = JsonUtils.getJson(date);
return json;
}
5.2.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字串之間的相互轉化。
程式碼測試,我們新建一個FastJsonDemo 類
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kuang.pojo.User;
import java.util.ArrayList;
import java.util.List;
public class FastJsonDemo {
public static void main(String[] args) {
//建立一個物件
User user1 = new User("wyl1號", 3, "男");
User user2 = new User("wyl2號", 3, "男");
User user3 = new User("wyl3號", 3, "男");
User user4 = new User("wyl4號", 3, "男");
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
System.out.println("*******Java物件 轉 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字串 轉 Java物件*******");
User jp_user1=JSON.parseObject(str2,User.class);
System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);
System.out.println("\n****** Java物件 轉 JSON物件 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name"));
System.out.println("\n****** JSON物件 轉 Java物件 ******");
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
}
}
6.攔截器
6.1.過濾器與攔截器的區別
SpringMVC的處理器攔截器類似於Servlet開發中的過濾器Filter,用於對處理器進行預處理和後處理。開發者可以自己定義一些攔截器來實現特定的功能。
過濾器與攔截器的區別:攔截器是AOP思想的具體應用。
過濾器
- servlet規範中的一部分,任何java web工程都可以使用
- 在url-pattern中配置了/*之後,可以對所有要訪問的資源進行攔截
攔截器
-
攔截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
-
攔截器只會攔截訪問的控制器方法, 如果訪問的是jsp/html/css/image/js是不會進行攔截的
6.2.自定義攔截器
我們要想自定義攔截器,要求必須實現HandlerInterceptor 介面。
6.2.1. 編寫一個普通類實現HandlerInterceptor 介面
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 {
//在請求處理的方法之前執行
//如果返回true執行下一個攔截器
//如果返回false就不執行下一個攔截器
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------處理前------------");
return true;
}
//在請求處理方法執行之後執行
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------處理後------------");
}
//在dispatcherServlet處理後執行,做清理工作.
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------清理------------");
}
}
6.1.2. 配置攔截器
<!--關於攔截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路徑及其子路徑-->
<!--/admin/* 攔截的是/admin/add等等這種 , /admin/add/user不會被攔截-->
<!--/admin/** 攔截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是攔截器-->
<bean class="com.wyl.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
6.2.3.控制器
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//測試攔截器的控制器
@Controller
public class InterceptorController {
@RequestMapping("/interceptor")
@ResponseBody
public String testFunction() {
System.out.println("控制器中的方法執行了");
return "hello";
}
}
6.2.3.前端 index.jsp
<a href="${pageContext.request.contextPath}/interceptor">攔截器測試</a>
6.3.攔截器的細節
6.3.1. 攔截器的放行
放行的含義是指,如果有下一個攔截器就執行下一個,如果該攔截器處於攔截器鏈的最後一個,則執行控制器中的方法。
6.3.2.攔截器中方法的說明
public interface HandlerInterceptor {
/**
* preHandle方法是controller方法執行前攔截的方法,按攔截器定義順序呼叫
* return true放行,執行下一個攔截器,如果沒有攔截器,執行controller中的方法進行業務處理。
* return false不放行,不會執行controller中的方法或呼叫其他的元件。
*/
default boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler
)
throws Exception {
return true;
}
/**
* postHandle是controller方法執行後執行的方法,在JSP檢視執行前,按攔截器定義逆序呼叫。
* 可以使用request或者response跳轉到指定的頁面
* 如果指定了跳轉的頁面,那麼controller方法跳轉的頁面將不會顯示。
*/
default void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable ModelAndView modelAndView
)
throws Exception {}
/**
* afterCompletion方法是在JSP執行後執行,按攔截器定義逆序呼叫
* 注意:因為結果頁面已經返回完了,不能在該方法使用request或者response再跳轉頁面,但可以在該方法中進行一些資源清理的操作。
*/
default void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable Exception ex
)
throws Exception {}
}
6.3.3. 攔截器的作用路徑
作用路徑可以通過在配置檔案中配置。
<!-- 配置攔截器的作用範圍 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" /><!-- 用於指定對攔截的url -->
<mvc:exclude-mapping path="" /><!-- 用於指定排除的url-->
<bean id="handlerInterceptorDemo1"
class="com.wyl.interceptor.HandlerInterceptorDemo1">
</bean>
</mvc:interceptor>
</mvc:interceptors>
6.3.4. 多個攔截器的執行順序
多個攔截器是按照配置的順序決定的。
6.3.4.1. 攔截器1 的程式碼
public class HandlerInterceptorDemo1 implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler
)
throws Exception {
System.out.println("攔截器 1: preHandle 攔截器攔截了");
return true;
}
@Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView
)
throws Exception {
System.out.println("攔截器 1: postHandle 方法執行了");
}
@Override
public void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex
)
throws Exception {
System.out.println("攔截器 1: afterCompletion 方法執行了");
}
}
6.3.4.2. 攔截器2 的程式碼:
public class HandlerInterceptorDemo2 implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler
)
throws Exception {
System.out.println("攔截器2: preHandle 攔截器攔截了");
return true;
}
@Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView
)
throws Exception {
System.out.println("攔截器2: postHandle 方法執行了");
}
@Override
public void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex
)
throws Exception {
System.out.println("攔截器2: afterCompletion 方法執行了");
}
}
6.3.4.3.配置攔截器的作用範圍
<mvc:interceptor>
<mvc:mapping *path*="/**" />*<!--* *用於指定對攔截的**url -->*
<bean *id*="handlerInterceptorDemo1" *class*="com.wyl.interceptor.HandlerInterceptorDemo1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping *path*="/**" />
<bean *id*="handlerInterceptorDemo2" *class*="com.wyl.interceptor.HandlerInterceptorDemo2"></bean>
</mvc:interceptor>
6.3.4.4.中斷流程測試
攔截器2 返回false
7.上傳檔案
7.1.匯入檔案上傳的jar包
<!--檔案上傳
commons-io 不屬於檔案上傳元件的開發jar 檔案,但Commons-fileupload 元件從1.1 版本開始,它
工作時需要commons-io 包的支援。
-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--servlet-api匯入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
7.2. 編寫檔案上傳的jsp 頁面
<h3>檔案上傳</h3>
<form action="user/fileupload" method="post" enctype="multipart/form-data">
選擇檔案:<input type="file" name="upload" /><br />
<input type="submit" value="上傳檔案" />
</form>
至少有一個檔案選擇域
以POST方式提交
表單的enctype必須為 multipart/form-data
7.3.控制器(非SpringMVC版)
package com.wyl.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller
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";
}
}
7.4.SpringMVC配置資訊
SpringMVC框架提供了MultipartFile物件,該物件表示上傳的檔案,要求變數名稱必須和表單file標籤的name屬性名稱相同。
<!-- 配置檔案解析器物件,要求id名稱必須是multipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 設定上傳檔案的最大尺寸為5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
<!-- property name="maxUploadSize" value="10485760"/ -->
</bean>
7.5.控制器程式碼(SpringMVC版)
/**
* SpringMVC方式的檔案上傳
*/
@RequestMapping(value="/fileupload2")
public String fileupload2(HttpServletRequest request,MultipartFile upload) throws Exception {
System.out.println("SpringMVC方式的檔案上傳...");
// 先獲取到要上傳的檔案目錄
String path = request.getSession().getServletContext().getRealPath("/uploads");
// 建立File物件,一會向該路徑下上傳檔案
File file = new File(path);
// 判斷路徑是否存在,如果不存在,建立該路徑
if(!file.exists()) {
file.mkdirs();
}
// 獲取到上傳檔案的名稱
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 把檔案的名稱唯一化
filename = uuid+"_"+filename;
// 上傳檔案
upload.transferTo(new File(file,filename));
return "success";
}
7.6.跨伺服器
準備兩個tomcat 伺服器,其中一個作為檔案伺服器,一個作為應用伺服器。
7.6.1.在檔案伺服器tomcat的web.xml中修改tomcat配置,允許讀寫操作。
7.6.2.匯入包
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
7.6.3.控制器
**
* SpringMVC跨伺服器方式的檔案上傳
*/
@RequestMapping(value="/fileupload3")
public String fileupload3(MultipartFile upload) throws Exception {
System.out.println("SpringMVC跨伺服器方式的檔案上傳...");
// 定義圖片伺服器的請求路徑
String path = "http://localhost:9090/day02_springmvc5_02image/uploads/";
// 獲取到上傳檔案的名稱
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 把檔案的名稱唯一化
filename = uuid+"_"+filename;
// 向圖片伺服器上傳檔案
// 建立客戶端物件(sun公司提供的jersey 包)
Client client = Client.create();
// 連線圖片伺服器
WebResource webResource = client.resource(path+filename);
// 上傳檔案 //String result = resource.put(String.class,uploadFile.getBytes());
webResource.put(upload.getBytes());
return "success";
}
7.7.下載
檔案下載步驟:
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 = "基礎語法.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="/download">點選下載</a>
測試,檔案下載OK,大家可以和我們之前學習的JavaWeb原生的方式對比一下,就可以知道這個便捷多了!
攔截器及檔案操作在我們開發中十分重要,一定要學會使用!
8.整合ssm
8.1.前期準備
環境:
- IDEA
- MySQL 8.0.18
- Tomcat 9
- Maven 3.6
建立資料庫:
CREATE DATABASE `wyl`;
USE `wyl`;
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`email` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`gender` int(255) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
8.1.專案搭建
8.1.1.建立專案
8.1.2.匯入相關的pom依賴
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- 依賴:junit,資料庫驅動,連線池,servlet,jsp,mybatis,mybatis-spring,spring -->
<!--資料庫驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<!-- 資料庫連線池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!--Servlet - JSP -->
<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>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!--spring-->
<!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
8.1.2.靜態資源匯出
8.1.3.專案結構
8.1.4.配置
8.1.4.1.mybatis
database.properties(資料庫配置檔案)
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://127.0.0.1:3306/wyl?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=wyl190204-
mybatis-config.xml(核心配置檔案)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--轉為駝峰-->
<!-- <settings>-->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/>-->
<!-- </settings>-->
<!--別名-->
<typeAliases>
<package name="com.wyl.pojo"/>
</typeAliases>
<!--對映器-->
<mappers>
<mapper class="com.wyl.dao.UsersMapper"></mapper>
</mappers>
</configuration>
8.1.4.2.spring
1、配置Spring整合MyBatis,我們這裡資料來源使用c3p0連線池;
2、我們去編寫Spring整合Mybatis的相關的配置檔案;spring-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置整合mybatis -->
<!-- 1.關聯資料庫檔案 -->
<context:property-placeholder location="classpath:database.properties"/>
<!-- 2.資料庫連線池 -->
<!--資料庫連線池
dbcp 半自動化操作 不能自動連線
c3p0 自動化操作(自動的載入配置檔案 並且設定到物件裡面)
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置連線池屬性 -->
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- c3p0連線池的私有屬性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 關閉連線後不自動commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 獲取連線超時時間 -->
<property name="checkoutTimeout" value="10000"/>
<!-- 當獲取連線失敗重試次數 -->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<!-- 3.配置SqlSessionFactory物件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入資料庫連線池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBaties全域性配置檔案:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 4.配置掃描Dao介面包,動態實現Dao介面注入到spring容器中 -->
<!--解釋 :https://www.cnblogs.com/jpfss/p/7799806.html-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 給出需要掃描Dao介面包 -->
<property name="basePackage" value="com.wyl.dao"/>
</bean>
</beans>
spring-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 掃描service相關的bean -->
<context:component-scan base-package="com.kuang.service" />
<!--BookServiceImpl注入到IOC容器中-->
<bean id="BookServiceImpl" class="com.kuang.service.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/>
</bean>
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入資料庫連線池 -->
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
8.1.4.3.spring-mvc
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<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">
<display-name>Archetype Created Web Application</display-name>
<!--1.註冊DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--關聯一個springmvc的配置檔案:【servlet-name】-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<!--啟動級別-1-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的請求;(不包括.jsp)-->
<!--/* 匹配所有的請求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>filter</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>filter</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">
<!--掃描註解所在包-->
<context:component-scan base-package="com.wyl.controller"/>
<!-- 讓Spring MVC不處理靜態資源 -->
<mvc:default-servlet-handler/>
<!--
支援mvc註解驅動
在spring中一般採用@RequestMapping註解來完成對映關係
要想使@RequestMapping註解生效
必須向上下文中註冊DefaultAnnotationHandlerMapping
和一個AnnotationMethodHandlerAdapter例項
這兩個例項分別在類級別和方法級別處理。
而annotation-driven配置幫助我們自動完成上述兩個例項的注入。
-->
<mvc:annotation-driven/>
<!--配置JSP檢視解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置檔案所在目錄-->
<property name="prefix" value="/WEB-INF/pages/"/>
<!--配置檔案的字尾名-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
8.1.1.4.整合
applicationContext.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">
<import resource="spring-dao.xml"/>
<import resource="spring-service.xml"/>
<import resource="springmvc-servlet.xml"/>
</beans>
8.2.程式碼實現
8.2.1.pojo
package com.wyl.pojo;
import com.oracle.webservices.internal.api.databinding.DatabindingMode;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @建立人 王延領
* @建立時間 2021/10/25
* 描述
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
private int id;
private String username;
private String password;
private String email;
private int gender;
}
8.2.2.dao
UsersMapper.java
import com.wyl.pojo.Users;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @建立人 王延領
* @建立時間 2021/10/25
* 描述
**/
public interface UsersMapper {
//增
int addUser(Users user);
//刪
int delUser(int id);
//改
int updateUser(Users user);
//查
Users queryUser(int id);
//集合
List<Users> queryUsers();
//查
List<Users> queryUserByName(String name);
}
UsersMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wyl.dao.UsersMapper">
<insert id="addUser" parameterType="Users">
insert into users(id,username,password,email,gender) values (#{id},#{username},#{password},#{email},#{gender});
</insert>
<delete id="delUser" parameterType="int">
delete from users where id=#{id}
</delete>
<update id="updateUser" parameterType="Users">
update users set username=#{username},password=#{password},email=#{email},gender=#{gender} where id=#{id}
</update>
<select id="queryUser" resultType="Users">
select * from users where id=#{id}
</select>
<select id="queryUsers" resultType="Users">
SELECT * FROM users
</select>
<select id="queryUserByName" resultType="Users">
select * from users where username like '%${name}%'
</select>
</mapper>
8.2.3.service
UsersService
package com.wyl.service;
import com.wyl.pojo.Users;
import java.util.List;
/**
* @建立人 王延領
* @建立時間 2021/10/25
* 描述
**/
public interface UsersService {
//增
int addUser(Users user);
//刪
int delUser(int id);
//改
int updateUser(Users user);
//查
Users queryUser(int id);
//集合
List<Users> queryUsers();
//查
List<Users> queryUserByName(String name);
}
UsersServiceImpl
package com.wyl.service.impl;
import com.wyl.dao.UsersMapper;
import com.wyl.pojo.Users;
import com.wyl.service.UsersService;
import org.omg.CORBA.PUBLIC_MEMBER;
import java.util.List;
/**
* @建立人 王延領
* @建立時間 2021/10/25
* 描述
**/
public class UsersServiceImpl implements UsersService {
private UsersMapper userMapper;
public void setUserMapper(UsersMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public int addUser(Users user) {
int i = userMapper.addUser(user);
return i;
}
@Override
public int delUser(int id) {
int i = userMapper.delUser(id);
return i;
}
@Override
public int updateUser(Users user) {
int i = userMapper.updateUser(user);
return i;
}
@Override
public Users queryUser(int id) {
return userMapper.queryUser(id);
}
@Override
public List<Users> queryUsers() {
return userMapper.queryUsers();
}
@Override
public List<Users> queryUserByName(String name)
{
return userMapper.queryUserByName(name);
}
}
8.2.4.controller
package com.wyl.controller;
import com.wyl.pojo.Users;
import com.wyl.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Comparator;
import java.util.List;
/**
* @建立人 王延領
* @建立時間 2021/10/25
* 描述
**/
@Controller
@RequestMapping("/user")
public class UsersController {
@Autowired
@Qualifier("UsersServiceImpl")
private UsersService userService;
@RequestMapping("/userList")
public String userList(Model model) {
List<Users> users = userService.queryUsers();
users.sort(Comparator.comparingInt(Users::getId));
model.addAttribute("list", users);
return "userList";
}
@RequestMapping("/toAddUser")
public String toAddUser() {
return "addUser";
}
@PostMapping("/addUser")
public String addUser(Users user) {
System.out.println("addUser =>" + user);
int i = userService.addUser(user);
if (i > 0) {
return "redirect:/user/userList";
}
return "error";
}
@RequestMapping("/toUpdateUser")
public String toUpdateUser(int id, Model model) {
Users user = userService.queryUser(id);
model.addAttribute("user", user);
return "updateUser";
}
@PostMapping("/updateUser")
public String updateUser(Users user) {
System.out.println("updateUser =>" + user);
int i = userService.updateUser(user);
if (i > 0) {
return "redirect:/user/userList";
}
return "error";
}
@GetMapping("/deleteUser")
public String deleteUser(int id) {
System.out.println("deleteUser =>" + id);
int i = userService.delUser(id);
if (i > 0) {
return "redirect:/user/userList";
}
return "error";
}
/**
* 查詢全部書籍,並且返回到一個書籍展示頁面
*/
@RequestMapping("/byName")
public String ByName(String name, Model model) {
List<Users> users = userService.queryUserByName(name);
if (users == null || users.size() == 0) {
model.addAttribute("error", "未查詢到使用者");
return "userList";
}
System.out.println("users =>" + users);
// 排序
users.sort(Comparator.comparingInt(Users::getId));
model.addAttribute("list", users);
return "userList";
}
}
8.3.page
userList.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/25
Time: 16:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>展示頁面</title>
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>使用者列表 ------ 顯示所有使用者</small>
</h1>
</div>
</div>
<div class="row">
<div class="col-md-4">
<a class="btn btn-primary" href="${pageContext.request.contextPath}/user/toAddUser">新增使用者</a>
</div>
<div class="col-md-2"></div>
<div class="col-md-6 right">
<form class="navbar-form navbar-right" method="get" action="${pageContext.request.contextPath}/user/byName">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" name="name">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-md-12">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>編號</th>
<th>名稱</th>
<th>密碼</th>
<th>郵箱</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<c:forEach var="user" items="${list}">
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.password}</td>
<td>${user.email}</td>
<td><a href="${pageContext.request.contextPath}/user/toUpdateUser?id=${user.id}">修改</a> | <a href="${pageContext.request.contextPath}/user/deleteUser?id=${user.id}">刪除</a></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
<div>${error}</div>
</div>
</body>
</html>
aaUser.jsp
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/25
Time: 16:09
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>新增頁面</title>
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>新增使用者</small>
</h1>
</div>
</div>
</div>
<form action="${pageContext.request.contextPath}/user/addUser" method="post">
姓名<input type="text" name="username" required><br>
密碼<input type="text" name="password" required><br>
郵箱<input type="text" name="email"><br>
年齡<input type="text" name="gender"><br>
<input type="submit" value="新增">
</form>
</div>
</body>
</html>
updateUser.jsp
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/25
Time: 16:12
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12">
<div class="page-header">
<h1>
<small>修改使用者</small>
</h1>
</div>
</div>
</div>
<form action="${pageContext.request.contextPath}/user/updateUser" method="post">
<input type="hidden" name="id" value="${user.id}">
名稱<input type="text" name="username" value="${user.username}"><br>
密碼<input type="text" name="password" value="${user.password}"><br>
郵箱<input type="text" name="email" value="${user.email}"><br>
年齡<input type="text" name="gender" value="${user.gender}"><br>
<input type="submit" value="修改">
</form>
</div>
</body>
</html>
error.jsp
<%--
Created by IntelliJ IDEA.
User: 17144
Date: 2021/10/25
Time: 16:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>ERROR頁面</h1>
</body>
</html>