寫在前面:本文簡單講解SpringMVC的響應數據處理,以及文件上傳與下載,響應JSON格式,異常處理,攔截器的介紹等。。
作者還在學習階段,如果寫得不好請見諒。
公衆號:小白編碼
本文目錄
第一章:響應數據和結果視圖
1. 返回字符串
- Controller方法返回字符串可以指定邏輯視圖的名稱,根據視圖解析器爲物理視圖的地址。
@RequestMapping(value="/hello")
public String sayHello() {
System.out.println("Hello SpringMVC!!");
// 跳轉到XX頁面
return "success";
}
UserController:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("testString")
public String testString(Model model){
System.out.println("testString執行了!!");
// 模擬從數據庫中查詢的數據
User user = new User();
user.setUsername("小白");
user.setPassword("123");
model.addAttribute("user",user);
return "success";
}
}
jsp:請求地址
<a href="user/testString">testString</a>
success.jsp:EL表達式取值
<h3>測試成功!</h3>
${requestScope.user.username}
${requestScope.user.password}
2. 無返回值情況
- 如果控制器的方法返回值編寫成void,執行程序報404的異常, 默認查找JSP頁面沒有找到。
- 默認會跳轉到 @RequestMapping(value="/initUpdate") initUpdate.jsp的頁面。
- 可以使用請求轉發或者重定向跳轉到指定的頁面
jsp:
<a href="user/testVoid">testVoid</a>
控制器:
/**
* 無返回值情況
* 請求轉發一次請求,不用編寫項目的名稱
* 請求重定向二次請求,需要獲取項目名稱
*/
@RequestMapping("testVoid")
public void testVoid(HttpServletRequest req, HttpServletResponse resp) throws Exception {
System.out.println("testVoid執行了!!");
// 編寫請求轉發的程序,
// req.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(req,resp);
// 重定向,不能直接進WEB-INF的文件夾
resp.sendRedirect(req.getContextPath()+"/index.jsp");
// 設置中文亂碼
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
// 直接會進行響應輸出流到頁面!
resp.getWriter().print("你好");
}
請求轉發成功:
重定向:
打開響應流頁面:
運行方式:
3 .返回ModelAndView對象
ModelAndView
對象是 Spring 提供的一個對象,可以用來調整具體的 JSP 視圖
jsp:
<a href="user/testModelAndView">testModelAndView</a>
控制器:
/**
* 返回ModelAndView
* @return
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
// 創建ModelAndView對象
ModelAndView mv = new ModelAndView();
System.out.println("testModelAndView方法執行了...");
// 模擬從數據庫中查詢出User對象
User user = new User();
user.setUsername("小鳳");
user.setPassword("456");
user.setAge(30);
// 把user對象存儲到mv對象中,也會把user對象存入到request對象
mv.addObject("user",user);
// 跳轉到success的.jsp頁面
mv.setViewName("success");
return mv;
}
測試結果:
第二章:SpringMVC框架提供的轉發和重定向
1. forward請求轉發
jsp:
<a href="user/testForward">testForward</a>
controller方法返回String類型,想進行請求轉發可以編寫成:
控制器:
/**
* 使用forward關鍵字進行請求轉發
* "forward:轉發的JSP路徑",不走視圖解析器了,所以需要編寫完整的路徑
* @return
* @throws Exception
*/
@RequestMapping("/testForward")
public String testForward() throws Exception {
System.out.println("testForward...");
// return "forward:/WEB-INF/pages/success.jsp";
return "forward:/WEB-INF/pages/success.jsp";
}
結果:
2. redirect重定向
jsp:
<a href="user/testRedirect">testRedirect</a>
控制器:
/**
* 重定向
* @return
* @throws Exception
*/
@RequestMapping("/testRedirect")
public String testRedirect() throws Exception {
System.out.println("testRedirect...");
return "redirect:/index.jsp";
// return "redirect:/user/findAll";
}
第三章:SpringMVC響應JSON數據
@ResponseBody 註解
DispatcherServlet會攔截到所有的資源,導致一個問題就是靜態資源(img、css、js)也會被攔截到,從而不能被使用。解決問題就是需要配置靜態資源不進行攔截,在springmvc.xml
配置文件添加如下配置:
mvc:resources
標籤配置不過濾location
元素表示webapp
目錄下的包下的所有文件mapping
元素表示以/static開頭的所有請求路徑,如/static/a 或者/static/a/b
<!-- 設置靜態資源不過濾 -->
<mvc:resources location="/css/" mapping="/css/**"/> <!-- 樣式 -->
<mvc:resources location="/img/" mapping="/img/**"/> <!-- 圖片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function () {
$("#btn").click(function () {
// alert("hello");
$.ajax({
//請求地址
url:"user/testAjax",
//表示發給服務器的數據
data:{"name":"小白","age":18},
//響應的數據類型
dataType: "json",
//設置字符集
contentType:"application/json;charset=UTF-8",
//表示請求類型
type: "post",
success:function (data) {
alert(data);
}
});
});
});
</script>
</head>
<body>
<button id="btn">發送ajax請求</button>
</body>
</html>
控制器:獲取請求體數據
/**
* 獲取請求體數據
* @return
* @throws Exception
*/
@RequestMapping("/testAjax")
public void testAjax(@RequestBody String body) throws Exception {
System.out.println(body);
}
導入依賴: json字符串
和JavaBean對象
互相轉換的過程中,需要使用jackson的jar包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
控制器:將請求過來的字符串轉換成JavaBean:
@Controller
public class HelloController {
@RequestMapping("/testResponseJson")
public void testResponseJson(@RequestBody User user){
System.out.println("Json字符封裝成javaBean:"+ user);
}
}
控制器:將JavaBean對象轉換成Json響應到客戶端:
/**
* 異步請求
*
* @return
* @throws Exception
*/
@RequestMapping(value = "/testAjax",method = RequestMethod.POST)
public @ResponseBody
User testAjax(@RequestBody User user){
// 客戶端發送ajax的請求,傳的是json字符串,後端把json字符串封裝到user對象中
System.out.println(user);
// 做響應,模擬查詢數據庫
user.setUsername("小黑");
user.setPassword("123");
//做響應
return user;
}
jsp:
<script type="text/javascript">
$(function () {
$("#btn").click(function () {
// alert("hello");
$.ajax({
//請求地址
url:"user/testAjax",
//表示發給服務器的數據
data:'{"username":"小白","password":"123","age":18}',
//響應的數據類型
dataType: "json",
//設置字符集
contentType:"application/json;charset=UTF-8",
//表示請求類型
type: "post",
success:function (data) {
alert(data);
alert(data.username);
alert(data.password);
alert(data.age)
}
});
});
});
</script>
第四章:文件上傳與下載
文件上傳前提:
form表單
的enctype
取值必須是:multipart/form-data
- 默認值是:
application/x-www-form-urlencoded
) enctype:
是表單請求正文的類型method
屬性取值必須是Post
C 提供一個文件選擇域<input type="file" />
當form表單的enctype取值不是默認值後,request.getParameter()將失效。
依賴導入:
<!-- 文件上傳-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
jsp:表單:
<%--enctype="multipart/form-data"
當form表單的enctype取值爲Mutilpart/form-data時,
請求正文內容就變成: 每一部分都是MIME類型描述的正文--%>
<form action="user/fileupload" method="post" enctype="multipart/form-data">
選擇文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上傳文件"/>
1.傳統方式文件傳輸:
控制器:
@RequestMapping("/fileupload")
public String fileupload(HttpServletRequest req) throws Exception {
System.out.println("測試成功!");
// 使用fileupload組件完成文件上傳
// 上傳的位置
String path = req.getSession().getServletContext().getRealPath("/uploads/");
//創建File對象,一會向該路徑下上傳文件
File file = new File(path);
// 判斷路徑是否存在,如果不存在,創建該路徑
if (!file.exists()) {
file.mkdir();
}
// 解析request對象,獲取上傳文件項
DiskFileItemFactory factory = new DiskFileItemFactory();//磁盤文件項工廠
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request(裝的都是文件項)
List<FileItem> items = upload.parseRequest(req);
//遍歷
for (FileItem item: items){
// 進行判斷,當前item對象是否是上傳文件項
if(item.isFormField()){
// 說明普通表單向
}else {
// 說明上傳文件項
// 獲取上傳文件的名稱
String filename = item.getName();
// 把文件的名稱設置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
item.write(new File(path,filename));
//刪除臨時文件
item.delete();
}
}
return "success";
}
2.SpringMVC文件傳輸
jsp表單:<input type="file" name="upload" />
name必須和MultipartFile的名稱一樣
<h3>SpringMVC方式文件上傳</h3>
<form action="user/fileupload2" method="post" enctype="multipart/form-data">
選擇文件:<input type="file" name="upload" /><br/>
<input type="submit" value="上傳" />
</form>
文件解析器配置:
<!-- 配置文件解析器對象,要求id名稱密續是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 設置最大上傳文件內存 10485760=10M -->
<property name="maxInMemorySize" value="10485760"></property>
</bean>
控制器:
@RequestMapping("/fileupload2")
public String fileupload2(HttpServletRequest req, MultipartFile upload) throws Exception {
System.out.println("測試成功!");
// 使用fileupload組件完成文件上傳
// 上傳的位置
String path = req.getSession().getServletContext().getRealPath("/uploads/");
//創建File對象,一會向該路徑下上傳文件
File file = new File(path);
// 判斷路徑是否存在,如果不存在,創建該路徑
if (!file.exists()) {
file.mkdir();
}
// 說明上傳文件項
// 獲取上傳文件的名稱
String filename = upload.getName();
// 把文件的名稱設置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
// 完成文件上傳
upload.transferTo(new File(file,filename));
return "success";
}
3.跨服務器文件上傳:
在實際開發中,我們會有很多處理不同功能的服務器。(注意:此處說的不是服務器集羣)
-
應用服務器: 負責部署我們的應用
-
數據庫服務器: 運行我們的數據庫
-
緩存和消息服務器: 負責處理大併發訪問的緩存和消息
-
文件服務器: 負責存儲用戶上傳文件的服務器。
流程:
1.配置一個新的工程,創建uploads文件夾
2.配置服務器:
3.導入開發需要的jar包
<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>
4.編寫文件上傳的JSP頁面:
<h3>跨服務器方式文件上傳</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
選擇文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上傳"/>
</form>
5.編寫控制器:
/**
* 跨服務器文件上傳
*
* @param upload
* @return
* @throws Exception
*/
@RequestMapping("/fileupload3")
public String fileupload3( MultipartFile upload) throws Exception {
System.out.println("跨服務器上傳成功!");
// 使用fileupload組件完成文件上傳
// 定義圖片服務器的請求路徑
String path = "http://localhost:9090/uploads/";
// 說明上傳文件項
// 獲取上傳文件的名稱
String filename = upload.getName();
// 把文件的名稱設置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
// 創建客戶端對象
Client client = Client.create();
//連接圖片服務器
WebResource webResource = client.resource(path + filename);
// 上傳文件
webResource.put(upload.getBytes());
return "success";
}
如果報405:在tomcat配置文件中加入這個參數
測試上傳成功:
第五章: SpringMVC異常處理
異常處理思路
- Controller調用service,service調用dao,異常都是向上拋出的,最終由
DispatcherServlet
找異常處理器進行異常的處理。
SpringMVC的異常處理:
jsp:
<h3>異常處理</h3>
<a href="user/testException">testException</a>
自定義異常類:
@Data
public class SysException extends Exception{
//存儲 提示信息
private String message;
public SysException(String message) {
this.message = message;
}
}
自定義異常處理器:實現HandlerExceptionResolver
接口
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 跳轉到具體頁面
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
SysException e = null;
//① a instanceof A:判斷對象a是否是類A的實例。如果是,返回true;如果不是,返回false。
//② 如果 a instanceof A返回true,則 a instanceof B也返回true.其中,類B是類A的父類。
if (ex instanceof SysException){
//強轉(如果ex是SysException的實例)
e = (SysException) ex;
}else {
e = new SysException("系統維護中...");
}
// 創建ModelAndView對象
ModelAndView mv = new ModelAndView();
// 把message信息存儲到mv對象中,也會把message對象存入到request域對象
mv.addObject("message",e.getMessage());
// 跳轉到異常頁面.jsp
mv.setViewName("error");
return mv;
}
}
配置異常處理器:
<!-- 配置異常處理器-->
<bean id="sysExceptionResolver" class="cn.codewhite.exception.SysExceptionResolver"/>
控制器:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testException")
public String testException() throws SysException{//往瀏覽器拋異常Exception
System.out.println("testException執行了!");
//模擬異常
try {
int i = 1 / 0;
} catch (Exception e) {
// 打印異常信息
e.printStackTrace();
// 拋出自定義異常信息
throw new SysException("查詢所有用戶出現了錯誤...");
}
return "success";
}
}
error.jsp:
<h1>${requestScope.message}</h1>
測試:
結果:跳轉到了異常頁面。
第六章:SpringMVC框架中的攔截器
Spring MVC 的處理器攔截器類似於Servlet開發中的過濾器Filter,用於對處理器進行預處理和後處理。
- 可以定義攔截器鏈,連接器鏈就是將攔截器按着一定的順序結成一條鏈,在訪問被攔截的方法時,攔截器鏈
中的攔截器會按着定義的順序執行。 - 過濾器是Servlet規範的一部分,任何框架都可以使用過濾器技術。
- 攔截器是SpringMVC框架獨有的。
- 過濾器配置了
/*
,可以攔截任何資源。 - 攔截器只會對控制器中的方法進行攔截。
- 它也是AOP思想的具體應用。
- 我們要想自定義攔截器, 要求必須實現:
HandlerInterceptor
接口。
過濾器與攔截器區別:
- 過濾器是servlet規範中的一部分,任何java web工程都可以使用
- 攔截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
- 過濾器在url-pattern中配置了**/***之後,可以對所有要訪問的資源攔截。
- 攔截器它是隻會攔截訪問的控制器方法,如果訪問的是jsp,html,css,image或者js是不會進行攔截的。
1.單個攔截器:
控制器:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testInterceptor")
public String testInterceptor(){
System.out.println("testInterceptor!");
return "success";
}
}
1.創建類,實現HandlerInterceptor
接口,重寫需要的方法
/**
* @author JUNSHI [email protected]
* @create 2020-05-30 14:35
*/
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 預處理 controller方法執行前
* return true放行,執行下一個攔截器,如果沒有,執行controller中的方法
* return false不放行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1執行了...");
return true;
}
}
2.在springmvc.xml中配置攔截器類
<!-- 配置攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 哪些方法進行攔截 默認請求鏈接的/user/下所有都攔截 -->
<mvc:mapping path="/user/*"/>
<!-- 哪些方法不進行攔截
<mvc:exclude-mapping path=""/>
-->
<!-- 註冊攔截器對象 -->
<bean class="cn.codewhite.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
運行結果:
HandlerInterceptor
接口中的方法
-
preHandle方法
是controller方法執行前攔截的方法-
可以使用request或者response跳轉到指定的頁面
-
return true
放行,執行下一個攔截器,如果沒有攔截器,執行controller中的方法。 -
return false
**不放行,**不會執行controller中的方法。
-
-
postHandle
是controller方法執行後執行的方法,在JSP視圖執行前。-
可以使用request或者response跳轉到指定的頁面
-
如果指定了跳轉的頁面,那麼controller方法跳轉的頁面將不會顯示。
-
-
postHandle
方法是在JSP執行後執行- request或者response不能再跳轉頁面了
2.多個攔截器:
多個攔截器執行順序:
index.jsp:
<h3>攔截器</h3>
<a href="user/testInterceptor">testInterceptor</a>
success.jsp:
<h3>執行成功!</h3>
<% System.out.println("success.jsp執行了"); %>
控制器:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testInterceptor")
public String testInterceptor(){
System.out.println("testInterceptor!");
return "success";
}
}
攔截器1:
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 預處理 controller方法執行前
* return true放行,執行下一個攔截器,如果沒有,執行controller中的方法
* return false不放行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("攔截器1:preHandle攔截器攔截了 前111");
return true;
}
/**
* 後處理方法,controller方法執行後,success.jsp執行之前
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("攔截器1:postHandle方法執行了 後111");
}
/**
* success.jsp頁面執行後,該方法會執行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("攔截器1:afterCompletion方法執行了 最後111");
}
}
攔截器2:
/**
* 自定義攔截器2
*/
public class MyInterceptor2 implements HandlerInterceptor {
/**
* 預處理 controller方法執行前
* return true放行,執行下一個攔截器,如果沒有,執行controller中的方法
* return false不放行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("攔截器2:preHandle攔截器攔截了 前222");
return true;
}
/**
* 後處理方法,controller方法執行後,success.jsp執行之前
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("攔截器2:postHandle方法執行了 後222");
}
/**
* success.jsp頁面執行後,該方法會執行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("攔截器2:afterCompletion方法執行了 最後222");
}
}
springmvc.xml:
<!-- 配置攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置第一個攔截器-->
<!-- 哪些方法進行攔截 默認請求鏈接的/user/下所有都攔截 -->
<mvc:mapping path="/user/*"/>
<!-- 哪些方法不進行攔截
<mvc:exclude-mapping path=""/>
-->
<!-- 註冊攔截器對象 -->
<bean class="cn.codewhite.interceptor.MyInterceptor1"/>
</mvc:interceptor>
<!-- 配置第二個攔截器-->
<mvc:interceptor>
<!-- 哪些方法進行攔截,url-->
<mvc:mapping path="/**"/>
<!-- 哪些方法不進行攔截
<mvc:exclude-mapping path=""/>
-->
<!-- 註冊攔截器對象 -->
<bean class="cn.codewhite.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
運行結果:
寫在後邊
以上都是SpringMVC的一些重要內容,如果需要SSM框架的PDF版筆記可以找我。