1. 文件上傳
1). 主要是CommonsMultipartResolver解析器依賴commons-fileupload和commons-io這兩個(gè)jar包
commons-fileupload-1.3.3.jar
commons-io-2.6.jar
2). 修改editItem.jsp如下
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!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>
<!-- 上傳圖片是需要指定屬性 enctype="multipart/form-data" -->
<%-- <form id="itemForm" action="${pageContext.request.contextPath }/updateItem.action" method="post"> --%>
<form id="itemForm" action="${pageContext.request.contextPath }/updateItem.action"
method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="${item.id }"/>修改商品信息:
<table width="100%" border="1">
<tr>
<td>商品名稱</td>
<td><input type="text" name="name" value="${item.name }"/></td>
</tr>
<tr>
<td>商品價(jià)格</td>
<td><input type="text" name="price" value="${item.price }"/></td>
</tr>
<tr>
<td>商品生產(chǎn)日期</td>
<td><input type="text" name="createtime"
value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/>
</td>
</tr>
<tr>
<td>商品圖片</td>
<td>
<c:if test="${item.pic != null }">
<img src="/pic/${item.pic }" width="100" height="100"/>
<br>
</c:if>
<input type="file" name="picture"/>
</td>
</tr>
<tr>
<td>商品簡(jiǎn)介</td>
<td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="提交"/>
</td>
</tr>
</table>
</form>
</body>
</html>
3). 多部件類型multipart解析
在springmvc.xml文件中添加:
<!-- 配置多媒體文件解析器 -->
<!-- 文件上傳 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 設(shè)置上傳文件的最大尺寸為5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
4). 創(chuàng)建文件保存的虛擬目錄
在上傳文件之前,首先要?jiǎng)?chuàng)建一個(gè)虛擬目錄來(lái)保存文件骨杂,這個(gè)虛擬目錄會(huì)對(duì)應(yīng)磁盤(pán)上的一個(gè)實(shí)際的目錄诱贿,在實(shí)際開(kāi)發(fā)中肯定會(huì)有一個(gè)服務(wù)器專門(mén)存儲(chǔ)資源的,在這里我們就用本地磁盤(pán)來(lái)保存文件疾嗅,然后映射一個(gè)虛擬目錄,用來(lái)在程序中指定獲取文件的路徑.
I. 先在Tomcat上點(diǎn)擊右鍵選擇clean...冕象,完成之后再雙擊Tomcat代承。
II. 選擇下方的Modules。
III. 點(diǎn)擊Add External Web Module...
IV. Document base選擇本機(jī)目錄渐扮,Path添加虛擬目錄论悴,在editItem.jsp中是/pic
V. 點(diǎn)擊確定后,如圖:
VI. 第二種方法就是在tomcat的配置文件中配置一下墓律,配置文件位置在tomcat目錄/conf/server.xml中:
<Context docBase="D:\picture" path="/pic" reloadable="true"/>
5). 后臺(tái)Controller方法
@RequestMapping(value = "/updateItem", method = { RequestMethod.POST, RequestMethod.GET })
public String updateItem(Item item, MultipartFile picture) throws Exception {
// 把圖片保存到圖片目錄下
// 保存圖片膀估,這個(gè)圖片的文件名可能會(huì)重復(fù),為每個(gè)文件生成一個(gè)新的文件名
String picName = UUID.randomUUID().toString();
// 截圖文件的擴(kuò)展名
String oriName = picture.getOriginalFilename();
String extName = oriName.substring(oriName.lastIndexOf("."));
// 保存文件
picture.transferTo(new File("D:\\picture\\" + picName + extName));
// 包文件名保存到數(shù)據(jù)庫(kù)
item.setPic(picName+extName);
service.updateItem(item);
// 重定向
// return "redirect:/itemList.action";
// 轉(zhuǎn)向
return "forward:/item/itemEdit.action";
}
6). 修改ItemMapper.xml文件
將
<update id="updateItem" parameterType="Item">
update items set name=#{name}, price=#{price}, detail=#{detail} where id = #{id}
</update>
修改為
<update id="updateItem" parameterType="Item">
update items set name=#{name}, price=#{price}, detail=#{detail}, pic=#{pic} where id = #{id}
</update>
7). 運(yùn)行項(xiàng)目測(cè)試
2. 前臺(tái)的json數(shù)據(jù)交互
1). 兩種形式
2). Jackson包
3). 配置json轉(zhuǎn)換器
<!-- 用于將對(duì)象轉(zhuǎn)換為 JSON -->
<bean id="stringConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="stringConverter" />
<ref bean="jsonConverter" />
</list>
</property>
</bean>
注意:如果使用<mvc:annotation-driven />注解驅(qū)動(dòng)的話就不用以上的配置
4). json交互的測(cè)試
I. 修改itemList.jsp耻讽,如下
jQuery下載
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!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>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-3.3.1.min.js"></script>
</head>
<body>
<form action="${pageContext.request.contextPath }/item/queryitem.action" method="post">
查詢條件:
<table width="100%" border="1">
<tr>
<td>商品id:<input type="text" name="item.id" /></td>
<td>商品名稱:<input type="text" name="item.name" /></td>
<td><input type="submit" value="查詢"/></td>
</tr>
</table>
商品列表:
<table width="100%" border="1">
<tr>
<td>選擇</td>
<td>商品名稱</td>
<td>商品價(jià)格</td>
<td>生產(chǎn)日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<c:forEach items="${itemList }" var="item" varStatus="s">
<%-- <tr>
<td><input type="checkbox" name="ids" value="${item.id }"/></td>
<td>${item.name }</td>
<td>${item.price }</td>
<td><fmt:formatDate value="${item.createtime }" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td>${item.detail }</td>
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
</tr> --%>
<tr>
<td><input type="checkbox" name="ids" value="${item.id }"/></td>
<td>
<input type="hidden" name="itemList[${s.index }].id" value="${item.id }"/>
<input type="text" name="itemList[${s.index }].name" value="${item.name }"/>
</td>
<td><input type="text" name="itemList[${s.index }].price" value="${item.price }"/></td>
<td><input type="text" name="itemList[${s.index }].createtime" value='<fmt:formatDate value="${item.createtime }" pattern="yyyy-MM-dd HH:mm:ss"/>'/></td>
<td><input type="text" name="itemList[${s.index }].detail" value="${item.detail }"/></td>
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
</tr>
</c:forEach>
</table>
</form>
<button onclick="sendJson()">JSON數(shù)據(jù)交互測(cè)試</button>
<script type="text/javascript">
function sendJson() {
$.ajax({
type:"post",
url:"${pageContext.request.contextPath }/jsonTest.action",
data:'{"id":"1","name":"電冰箱","price":"1999"}',
contentType:"application/json;charset=utf-8",
success:function(data) {
alert(data.id + ":" + data.name);
}
});
}
</script>
</body>
</html>
II. 修改文件路徑
將原在/WebContent/WEB-INF/路徑下的css,image,js文件夾玖像,移至/WebContent/路徑下
III. 在ItemController中創(chuàng)建方法
// JSON數(shù)據(jù)交互
// @RequestBody: 接收J(rèn)SON數(shù)據(jù)并轉(zhuǎn)換為pojo對(duì)象
// @ResponseBody: 相應(yīng)JSON數(shù)據(jù),把POJO對(duì)象轉(zhuǎn)換為JSON數(shù)據(jù)并響應(yīng)
@RequestMapping("/jsonTest")
@ResponseBody
public Item jsonTest(@RequestBody Item item){
System.out.println(item.toString());
return item;
}
IV. 測(cè)試結(jié)果:
前臺(tái):
后臺(tái):
3. Restful
1). 設(shè)計(jì)指南
在Restful之前的操作:
http://127.0.0.1/user/query/1 GET 根據(jù)用戶id查詢用戶數(shù)據(jù)
http://127.0.0.1/user/save POST 新增用戶
http://127.0.0.1/user/update POST 修改用戶信息
http://127.0.0.1/user/delete GET/POST 刪除用戶信息
RESTful用法:
http://127.0.0.1/user/1 GET 根據(jù)用戶id查詢用戶數(shù)據(jù)
http://127.0.0.1/user POST 新增用戶
http://127.0.0.1/user PUT 修改用戶信息
http://127.0.0.1/user DELETE 刪除用戶信息
之前的操作是沒(méi)有問(wèn)題的,大神認(rèn)為是有問(wèn)題的,有什么問(wèn)題呢?你每次請(qǐng)求的接口或者地址,都在做描述,例如查詢的時(shí)候用了query,新增的時(shí)候用了save,其實(shí)完全沒(méi)有這個(gè)必要,我使用了get請(qǐng)求,就是查詢.使用post請(qǐng)求,就是新增的請(qǐng)求,我的意圖很明顯,完全沒(méi)有必要做描述,這就是為什么有了restful.
2). 編寫(xiě)Restful風(fēng)格的代碼
I. 修改itemList.jsp中
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
修改為
<td><a href="${pageContext.request.contextPath }/itemEdit/${item.id}">修改</a></td>
II. 在web.xml配置文件中新增
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- /:攔截所有請(qǐng)求齐饮,不包括jsp捐寥。/*:攔截所有請(qǐng)求,包括jsp祖驱,應(yīng)該配置"/" -->
<url-pattern>/</url-pattern>
</servlet-mapping>
III. 修改editItem的方法
@RequestMapping("/itemEdit/{id}")
// 如果id和方法的形參一直握恳,@PathVariable注解中可以不寫(xiě)內(nèi)容
public String editItem(@PathVariable("id")Integer ids, Model model){
// 調(diào)用服務(wù)
Item item = service.getItemById(ids);
// 把數(shù)據(jù)傳遞給頁(yè)面,需要用到Model接口
model.addAttribute("item", item);
// 返回邏輯視圖
return "editItem";
}
IV. 設(shè)置一下不讓SpringMVC解析靜態(tài)資源捺僻。SpringMVC的<mvc:resources mapping="" location="">
標(biāo)簽可實(shí)現(xiàn)對(duì)靜態(tài)資源進(jìn)行映射訪問(wèn).
<!-- 配置資源映射 -->
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/image/" mapping="/image/**"/>
V. 測(cè)試
4. 攔截器的定義和配置
1). 定義:攔截器要實(shí)現(xiàn)HandlerInterceptor接口乡洼,并實(shí)現(xiàn)該接口中提供的三個(gè)方法
public class Interceptor1 implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("Interceptor1 preHandle......");
// 執(zhí)行的時(shí)機(jī)是在Handler執(zhí)行之前放行此方法
// 返回值:true,放行不攔截匕坯,正常執(zhí)行Handler進(jìn)行處理
// 返回值:false束昵,攔截,Handler不能正常處理
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// Handler 執(zhí)行之后葛峻,在返回ModelAndView之前锹雏,對(duì)modelAndView進(jìn)行處理
System.out.println("Interceptor1 postHandle......");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 返回ModelAndView之后
// Handler執(zhí)行過(guò)程如果出現(xiàn)異常,可以在此處理異常
System.out.println("Interceptor1 afterCompletion......");
}
}
- preHandle方法:該方法執(zhí)行的時(shí)機(jī)是在Handler執(zhí)行之前執(zhí)行术奖〗缸瘢可以用于身份認(rèn)證轻绞、身份授權(quán)等。比如如果認(rèn)證沒(méi)有通過(guò)表示用戶沒(méi)有登錄佣耐,需要此方法攔截不再往下執(zhí)行(return false)政勃,否則就放行(return true)。
- postHandle方法:該方法執(zhí)行的時(shí)機(jī)是在Handler執(zhí)行之后兼砖,在返回ModelAndView之前執(zhí)行奸远,可以看到該方法中有個(gè)modelAndView的形參。應(yīng)用場(chǎng)景:從modelAndView出發(fā)讽挟,將公用的模型數(shù)據(jù)(比如菜單導(dǎo)航之類的)在這里傳到視圖懒叛,也可以在這里統(tǒng)一指定視圖。
- afterCompletion方法:返回ModelAndView之后執(zhí)行戏挡。應(yīng)用場(chǎng)景:統(tǒng)一異常處理(即Handler執(zhí)行過(guò)程中出現(xiàn)異常芍瑞,可以在此處理異常),統(tǒng)一日志處理等褐墅。
2). 配置攔截器
- 某種HandlerMapping配置攔截器
在springmvc.xml文件中配置
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="handlerInterceptor1"/>
<ref bean="handlerInterceptor2"/>
</list>
</property>
</bean>
<bean id="handlerInterceptor1" class="com.mazaiting.interceptor.Interceptor1"/>
<bean id="handlerInterceptor2" class="com.mazaiting.interceptor.Interceptor2"/>
- 所有HandlerMapping配置全局?jǐn)r截器
在springmvc.xml文件中配置
<!-- 配置攔截器 -->
<mvc:interceptors>
<!-- 按照配置的順序執(zhí)行攔截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.mazaiting.interceptor.Interceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.mazaiting.interceptor.Interceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
注意:path=”/**”表示攔截所有的url包括子url路徑拆檬。在實(shí)際開(kāi)發(fā)中,一般我們都用這種配置妥凳,<mvc:mapping>中指定要攔截的url即可
3). 測(cè)試
總結(jié):當(dāng)所有攔截器都放行的時(shí)候竟贯,preHandle方法是按照配置的順序執(zhí)行的;而另外兩個(gè)方法按照配置的順序逆向執(zhí)行逝钥。
4).有一個(gè)攔截器不放行
總結(jié)
- 由于攔截器1和2放行屑那,所以攔截器3的preHandle才能執(zhí)行。也就是說(shuō)前面的攔截器放行了艘款,后面的攔截器才能執(zhí)行preHandle方法持际。
- 攔截器3不放行,所以其另外兩個(gè)方法沒(méi)有被執(zhí)行哗咆。即如果某個(gè)攔截器不放行蜘欲,那么它的另外兩個(gè)方法就不會(huì)被執(zhí)行。
- 只要有一個(gè)攔截器不放行晌柬,所有攔截器的postHandle方法都不會(huì)執(zhí)行姥份,但是只要執(zhí)行過(guò)preHandle并且放行的,就會(huì)執(zhí)行afterCompletion方法年碘。
5). 三個(gè)攔截器都不放行
總結(jié)
總結(jié)
- preHandle按攔截器定義順序調(diào)用
- postHandler按攔截器定義逆序調(diào)用
- afterCompletion按攔截器定義逆序調(diào)用
- postHandler在攔截器鏈內(nèi)所有攔截器返回true才調(diào)用
- afterCompletion只有preHandle返回true才調(diào)用
5. 攔截器應(yīng)用實(shí)例
1). 編寫(xiě)login.jsp頁(yè)面
<%@ 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>
<form action="${pageContext.request.contextPath }/user/login" method="post">
<label>用戶名</label>
<input type="text" name="username"/>
<br/>
<label>密碼</label>
<input type="password" name="password"/>
<br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
2). 編寫(xiě)實(shí)現(xiàn)用戶登錄的Controller
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/showlogin")
public String showLogin(){
return "login";
}
@RequestMapping("/login")
public String userLogin(String username,String password, HttpSession session) {
// 判斷用戶名和密碼是否正確
System.out.println(username + " : " + password);
// 正確澈歉,向session中寫(xiě)入用戶信息
session.setAttribute("username", username);
// 返回登錄成功頁(yè)面,或者跳轉(zhuǎn)至商品列表頁(yè)面
return "redirect:/itemList.action";
}
}
3). 登錄驗(yàn)證攔截器的實(shí)現(xiàn)
public class LoginInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String uri = request.getRequestURL().toString();
// 如果用戶未登錄屿衅,則跳轉(zhuǎn)到登錄頁(yè)面埃难。跳轉(zhuǎn)過(guò)程可能被攔截,所以要做判斷
if (uri.contains("login")) {
return true;
}
System.out.println("LoginInterceptor preHandle...");
// 用戶攔截請(qǐng)求,判斷用戶是否登錄
HttpSession session = request.getSession();
String username = (String) session.getAttribute("username");
if (!"".equals(username) && null != username) {
// 已經(jīng)登錄凯砍,放行
return true;
}
// 如果用戶未登錄箱硕,則跳轉(zhuǎn)到登錄頁(yè)面
response.sendRedirect(request.getContextPath() + "/user/showlogin");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("LoginInterceptor postHandle...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("LoginInterceptor afterCompletion...");
}
}
4). 配置攔截器
<!-- 配置攔截器 -->
<mvc:interceptors>
<!-- 配置登錄攔截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.mazaiting.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>