json數據交互
案例實現
- 導入pom依賴
說明:springmvc框架,默認使用HttpMessageConverter消息轉換器,進行json格式數據轉換。需要加入jackson依賴包支持
<!--依賴管理-->
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<!--Apache的文件解析器-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
- SpringMVC核心配置文件
<?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 http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- bean definitions here -->
<!--開啓包掃描註解-->
<context:component-scan base-package="cn.itcast.controller"></context:component-scan>
<!--springmvc的註解驅動-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--視圖解析器的前綴和後綴-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"></property>
<property name="prefix" value="/WEB-INF/jsp/"></property>
</bean>
<!--前端控制器是/,所以要釋放靜態資源-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
</beans>
- web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--配置前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--將springmvc的配置文件交給前端控制器-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringConfig.xml</param-value>
</init-param>
</servlet>
<!--攔截規則-->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--亂碼過濾器-->
<filter>
<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- log4j日誌文件
### direct log messages to stdout ###
### 輸出源的配置 語法 log4j.appender.輸出源的名字=輸出源的實現類 ###
### log4j.appender.輸出源的名字.屬性=屬性值 ###
log4j.appender.a=org.apache.log4j.ConsoleAppender
log4j.appender.a.Target=System.out
log4j.appender.a.layout=org.apache.log4j.PatternLayout
log4j.appender.a.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=/home/travel.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
### 日誌記錄器的配置,固定語法 log4j.rootLogger=輸出級別, 輸出源,輸出源... ###
log4j.rootLogger=debug, a,file
- MyController
@Controller
public class MyController {
@RequestMapping("/demo")
public String demo() {
return "demo";
}
@ResponseBody //直接聲明一個方法,返回值類型是java實體對象類型.在方法上添加@ResponseBody註解通過springmvc轉換json
@RequestMapping("/returnJson")
public Item returnJson() {
Item item = new Item();
item.setName("耳機");
item.setPrice(1000);
item.setDetail("詳情");
return item;
}
@RequestMapping("/getJson")
@ResponseStatus(HttpStatus.OK)//void類型,並且沒有響應體
public void getJson(@RequestBody Item item) { //@RequestBody 讓springmvc將請求中的json轉換成java中的對象
System.out.println(item);
}
}
如果一個controller中所有的方法全部都是json返回值,我們直接使用@RestController來替代之前的@Controller
restful支持
restful介紹
- restful是一種軟件設計風格
- restful根據HTTP請求方法:
POST/GET/PUT/DELETE,定義了資源的操作方法:新增/查詢/修改/刪除 - restful風格的優點:
結構清晰、符合標準、易於理解、 擴展方便、請求的url更加簡潔,得到越來越多網站的採用
案例實現
步驟:
/**
* restful風格:
* 需求:
* /item/1 get 查詢id爲1的商品信息
* /item/1 delete 刪除id爲1的商品
* /item/1 put 更新id爲1的商品
* /item post 新增
*
* 步驟:
* 1.後臺需要4個方法來處理請求.但是這4個方法映射的路徑是一樣,只是限定請求的方式不一樣
* 2.前端發送請求,請求的地址一樣,但是請求的方式不一樣:
* a.通過rest插件發送put和delete請求
* b.springmvc提供了一個HiddenHttpMethodFilter,將所有的POST請求轉換成對應的post或者delete或者get或者put請求
* 根據POST請求中的_method參數的值進行轉換
*/
RestfulController
@Controller
public class RestfulController {
@RequestMapping(value = "/item/{id}", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
public void queryItemById(@PathVariable("id") String id) {
System.out.println("查詢商品:" + id);
}
@RequestMapping(value = "/item/{id}", method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.OK)
public void deleteItemById(@PathVariable String id) {
System.out.println("刪除商品:" + id);
}
@RequestMapping(value = "/item/{id}", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.OK)
public void updateItemById(@PathVariable String id) {
System.out.println("修改商品:" + id);
}
@RequestMapping(value = "/item/{id}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public void add() {
System.out.println("添加商品");
}
}
前端頁面請求:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/item/1" method="post">
<input type="hidden" name="_method" value="GET">
<input type="submit" value="get請求">
</form>
<form action="/item/2" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="delete請求">
</form>
<form action="/item/3" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="put請求">
</form>
<form action="/item/1" method="post">
<input type="hidden" name="_method" value="POST">
<input type="submit" value="post請求">
</form>
</body>
</html>
web.xml
請求方式過濾器
<!--請求方式過濾器-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
@PathVariable註解
請求中,路徑中的變量
路徑中的變量:
* 變量格式 : {變量名}
*
* 獲取路徑中的變量格式 @PathVariable(變量名)
* 如果變量名和方法名一樣, 直接寫@PathVariable
文件上傳
servlet中的文件上傳
-
前端 a.請求的方式必須是post類型. b.inpute type=file 文件標籤 c.enctype=multipart/form-data
-
後臺servlet a.在servlet上添加一個註解,用來解析文件上傳的這種數據格式類型 b.直接使用request.getPart();獲取文件
文件上傳三要素
- 表單的提交方式 method=“POST”
- 表單的enctype屬性是多部分表單形式 enctype=“multipart/form-data"
- 表單項(元素)type=“file”
<form action="" method="post" enctype="multipart/form-data">
姓名:<input type="text" name="username"> <br>
頭像:<input type="file" name="picFile"> <br>
</form>
SpringMVC實現文件上傳
案例實現
步驟:
/**
* springmvc的文件上傳:
* 前端:
* a.請求的方式必須是post類型.
b.inpute type=file 文件標籤
c.enctype=multipart/form-data
*
* 後臺:
* springmvc是通過apache的fileUpload依賴來解析文件的.
* 1.需要引入apache的fileupload依賴
* 2.配置一個文件解析器
* 3.直接在handler中聲明MultipartFile 類型的變量,然後直接操作
*/
pom依賴
<!--apache的文件解析器-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
springMVC.xml
<!--配置文件解析器-->
<!--id:必須是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--限制文件上傳的大小 字節-->
<property name="maxUploadSize" value="10240000"></property>
<!--上傳的文件名的編碼-->
<property name="defaultEncoding" value="utf-8"></property>
</bean>
UploadFileController
@Controller
public class UploadFileController {
@ResponseStatus(HttpStatus.OK)
@RequestMapping("/updateItem.do")
public void updateItem(Item item, @RequestParam("img") MultipartFile pictureFile) {
System.out.println("表單參數插入到數據庫:" + item);
//獲取源文件名
String originalFilename = pictureFile.getOriginalFilename();
//保存圖片
try {
pictureFile.transferTo(new File("d://" + originalFilename));
} catch (IOException e) {
e.printStackTrace();
}
}
}
統一異常處理
概述
-
請求流程:
客戶端(瀏覽器)–>前端控制器(DispatcherServlet)–>表現層(controller)–>業務層(service)–>持久層(dao) -
處理思路:
從持久層dao開始,每一層發生異常都向上一層拋出,一直拋到前端控制器(DispatcherServlet)。到此不能再拋出,我們不能把異常拋給用戶
在前端控制器需要進行異常處理,前端控制器是中央處理器,不負責具體的業務處理,因此在前端控制器需要調用異常處理器進行異常處理,最終返回一個友好的異常提示頁面,提示用戶
案例實現
需求:根據商品id查詢商品,如果查詢不到商品,拋出商品不存在異常
步驟:
- 1.自定義異常
- 2.拋出運行時異常
- 3.自定義異常處理器,實現HandlerExceptionResolver接口
- 4.在springmvc中配置當前異常處理器對象
NoResultException
//自定義一個異常類
public class NoResultException extends Exception {
public NoResultException(String message) {
super(message);
}
}
Controller
@Controller
public class ExceptionController {
@ResponseStatus(HttpStatus.OK)
@RequestMapping("/findItemById")
public void findItemById(Integer id) throws NoResultException {
if (id > 5) {
System.out.println("查詢id爲" + id + "的商品不存在");
//throw new NoResultException("查詢id爲" + id + "的商品不存在");
} else {
System.out.println("查詢id爲" + id + "的商品信息");
}
}
}
MyExceptionResolver
//自定義異常處理器,捕獲到的所有異常,都在這裏統一處理
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
//需要判斷異常的類型
if (ex instanceof NoResultException) {
//獲取業務中的錯誤信息
String message = ex.getMessage();
//保存數據
modelAndView.addObject("errorMsg", message);
} else if (ex instanceof MaxUploadSizeExceededException) {
modelAndView.addObject("errorMsg", "上傳的圖片過大");
}
//錯誤的頁面視圖
modelAndView.setViewName("error");
return modelAndView;
}
}
SpringMVC.xml
<!--配置異常處理器-->
<bean id="exceptionResolver" class="cn.itcast.exceptionHandler.MyExceptionResolver"></bean>
SpringMVC攔截器
概述
- springmvc框架中的攔截器,相當於web階段學習的過濾器(filter),可以實現前置增強和後置增強功能
- 在springmvc框架中,攔截器可以對處理器方法執行預處理(前置增強),和執行後處理(後置增強)
-
web開發中過濾器的作用: 在請求訪問目標資源之前進行攔截,一般都是通用性功能的抽取。(多個請求共有功能的抽取) 例如亂碼的處理,用於登錄的判斷,權限的判斷。。。。
-
在springmvc中,只有一個servlet。所有的請求,都是經過servlet再派發到controller。 ItemController進行攔截。 /item/save /item/delete
快速入門
需求:
- 創建一個demo級別的handler
- 創建一個類,實現攔截器接口 HandlerInterceptor
- 在springmvc.xml中配置攔截器
Controller
@Controller
@RequestMapping("/interceptor")
public class InterceptorController {
@RequestMapping("/demo")
public String demo(Model model) {
model.addAttribute("msg", "controller");
System.out.println("經過了controller");
return "demo";
}
}
interceptor
//攔截器
public class MyInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("在controller的handler之前執行");
return true; //返回true,表示放行.
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("在controller的handler之後執行,但是在視圖渲染之前");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("在視圖渲染之後做這個功能");
}
}
/**輸出結果爲:
* 在controller的handler之前執行
* 經過了controller
* 在controller的handler之後執行,但是在視圖渲染之前
* 2020-06-23 21:04:01,587 [http-nio-8080-exec-1] [org.springframework.web.servlet.DispatcherServlet]-[DEBUG] Rendering view [org.springframework.web.servlet.view.InternalResourceView: name 'demo'; URL [/WEB-INF/jsp/demo.jsp]] in DispatcherServlet with name 'DispatcherServlet'
* 2020-06-23 21:04:01,587 [http-nio-8080-exec-1] [org.springframework.web.servlet.view.InternalResourceView]-[DEBUG] Added model object 'msg' of type [java.lang.String] to request in view with name 'demo'
* 2020-06-23 21:04:01,588 [http-nio-8080-exec-1] [org.springframework.web.servlet.view.InternalResourceView]-[DEBUG] Forwarding to resource [/WEB-INF/jsp/demo.jsp] in InternalResourceView 'demo'
* 在視圖渲染之後做這個功能
*
*
*
*/
SpringMVC.xml
<!--
配置攔截器
聲明攔截器配置
-->
<mvc:interceptors>
<!-- 配置單個攔截器-->
<mvc:interceptor>
<!-- 配置攔截器攔截的路徑-->
<mvc:mapping path="/interceptor/*"/>
<!-- 配置攔截器對象-->
<bean class="cn.itcast.interceptors.MyInterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>
攔截器作用方法說明
攔截器鏈
<!--
配置攔截器
聲明攔截器配置
攔截器鏈:多個攔截器組成的整體. 按照上下的配置順序
-->
<mvc:interceptors>
<!-- 配置單個攔截器-->
<mvc:interceptor>
<!-- 配置攔截器攔截的路徑-->
<mvc:mapping path="/interceptor/*"/>
<!-- 配置攔截器對象-->
<bean class="cn.itcast.interceptors.MyInterceptor1"></bean>
</mvc:interceptor>
<!-- 配置單個攔截器-->
<mvc:interceptor>
<!-- 配置攔截器攔截的路徑-->
<mvc:mapping path="/interceptor/*"/>
<!-- 配置攔截器對象-->
<bean class="cn.itcast.interceptors.MyInterceptor2"></bean>
</mvc:interceptor>
<!-- 配置單個攔截器-->
<mvc:interceptor>
<!-- 配置攔截器攔截的路徑-->
<mvc:mapping path="/interceptor/*"/>
<!-- 配置攔截器對象-->
<bean class="cn.itcast.interceptors.MyInterceptor3"></bean>
</mvc:interceptor>
</mvc:interceptors>
攔截器應用實現
案例需求
-
用戶訪問商品列表數據,判斷用戶是否登錄: 1.如果用戶已經登錄,直接訪問商品列表數據 2.如果用戶未登錄,先到登錄頁面執行登錄。成功登錄以後再訪問商品列表數據
代碼實現
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--配置前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--讀取配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMvc.xml</param-value>
</init-param>
</servlet>
<!--配置攔截規則-->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
SpringMVC.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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 http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--開啓註解掃描-->
<context:component-scan base-package="cn.itcast"></context:component-scan>
<!--springmvc的註解驅動-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--攔截路徑是/,所以開啓加載靜態資源-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!--配置視圖解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前綴和後綴-->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/item/*"/>
<bean class="cn.itcast.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
UserController
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/goToLogin")
public String goToLogin() {
return "login";
}
@RequestMapping("/login")
public String login(HttpSession session) {
//表示登錄成功
session.setAttribute("user","user");
return "list";
}
}
ItemController
@Controller
@RequestMapping("/item")
public class ItemController {
@RequestMapping("/goToItemList")
public String goToItemList() {
//商品信息頁面
return "list";
}
}
LoginInterceptor
//登錄攔截器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判斷登錄權限
Object user = request.getSession().getAttribute("user");
//判斷
if (user != null) {
//登錄成功
return true;
} else {
//登錄失敗
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}