---1-1 前端交互設計--------------------------------------------------------------
WEB相關課程:
1. 前端交互設計
2. Restful
3. SpringMVC
4. bootstrap + jquery
---1-2 學習Restful接口設計---------------------------------------------------------------
1.什么是Restful接口:
1.興起於Rails
2.一種優雅的URI表達方式
3.資源的狀態和狀態轉移
Restful示例
GET /seckill/list
2.Restful規范
GET->查詢操作
POST->添加/修改操作
PUT->修改操作
DELETE->刪除操作
POST和PUT一般情況下沒有太嚴格的區分,PUT和POST體現在冪等性上
3.URL設計
/模塊/資源/{標示}/集合1/... ...
標示:表示出是哪一個資源 集合:對該資源進行什么操作?或者說指該資源的哪一部分......
/user/{uid}/frends->frends list
/user/{uid}/followers->followers list
4.秒殺API的URL設計
GET / seckill/ list 秒殺列表
GET / seckill/{id}/ detail 詳情頁
GET / seckill/time/now 系統時間
GET / seckill/{id}/exposer 暴露秒殺
GET / seckill/{id}/{md5}/execution 執行秒殺
---2-1 使用SpringMVC理論---------------------------------------------------------------
1.圍繞Handler開發
Handler -> 數據Model
頁面View
2.SpringMVC運行流程
3.HTTP請求地址映射原理
4.注解映射技巧
@RequestMapping注解:
(1)支持標准的URL
(2)Ant風格URL(即?,*,**等字符)
(3)帶{xxx}占位符的URL。
例如:
/user/*/creation
匹配/user/aaa/creation /user/bbb/creation等URL
/user/**/creation
匹配/user/creation /user/aaa/bbb/creation 等URL
/user/{userId}
匹配user/123,user/abc等URL。 ID以參數形式傳入
/company/{companyId}/user/{userId}/detail
匹配/company/123/user/456/detail等URL
5.請求方法細節處理
1.請求參數綁定
2.請求方式限制
3.請求轉發和重定向
4.數據模型賦值
5.返回json數據
6.cookie訪問
藍色:{seckillId},@PathVariable("seckillId")綁定方法的參數,對應到URL的占位符
綠色:method = RequestMethod.GET 只允許GET方法訪問
黃色Model model:返回給用戶的數據
紅色:redirect和forward 通過字符串控制 請求轉發和重定向
return "detail";//view 字符串返回jsp頁面detail.jsp
6.返回JSON數據
produces = {"application/json;charset=UTF-8"}告訴瀏覽器這是一個application/json,編碼為UTF-8
@ResponseBody 返回JSON數據
7.Cooki訪問:
@CookieValue(value = "killPhone",required = false)
1) required = false,不強制傳入"killPhone" 這個cookie
沒有killPhone這個cookie時,不進行攔截
2) 默認情況系,value = “killPhone”寫入之后,會強制匹配,cookie中沒有killPhone會報異常
---2-2 整合配置SpringMVC框架---------------------------------------------------------------
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true"> <!-- 修改servlet版本為3.1 --> <!-- 配置DispatcherServlet --> <servlet> <servlet-name>seckill-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置springMVC需要加載的配置文件 spring.dao.xml,spring-service.xml,spring-web.xml Mybatis -> spring -> springMVC(springMVC就是spring) --> <!-- 參數 加載配置:spring resouece體系下的前綴classpath spring/下的spring-開頭的配置文件 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-*.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>seckill-dispatcher</servlet-name> <!-- 默認匹配所有請求 --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
spring-web.xml
spring官方文檔:
http://docs.spring.io/spring/docs/4.2.9.RELEASE/spring-framework-reference/htmlsingle/
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" 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-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 配置springMVC --> <!-- 1:開啟SpringM注解模式 --> <!-- 簡化配置: (1)自動注冊DefaultAnnotationHandlerMapping(映射),AnnotationMethodHandlerAdapter(基於注解方法的Handler適配器) (2)默認提供一系列功能:數據綁定,數字和日期的format @NumberFormat,@DataTimeFormat, xml,json默認讀寫支持。 --> <mvc:annotation-driven/> <!-- 2:靜態資源默認servlet配置 2.1:加入對靜態資源的處理:js,gif,png 2.2:允許使用"/"做整體映射 --> <!-- servle-mapping 映射路徑:"/" (springMVC基本上讓用"*.action"這樣的注解) 使用"/"需要使用靜態資源默認servlet配置--> <mvc:default-servlet-handler/> <!--3:配置jsp顯示ViewResolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property> <property name="prefix" value="/WEB-INF/jsp"/> <property name="suffix" value=".jsp"/> </bean> <!-- 4:掃描web相關的bean --> <context:component-scan base-package="org.seckill.web"/> </beans>
---3-1 使用SpringMVC實現Restful接口---------------------------------------------------------------
springMVC:Spring MVC 中的 forward 和 redirect
http://blog.csdn.net/zzjjiandan/article/details/19491253
轉自 [Spring MVC] - view的redirect和forward
可以通過redirect/forward:url方式轉到另一個Action進行連續的處理。
可以通過redirect:url 防止表單重復提交 。
寫法如下:
return "forward:/order/add";
return "redirect:/index.jsp";
帶參數重定向--RedirectAttributes
用戶保存或修改后,為了防止用戶刷新瀏覽器(F5)導致表單重復提交,一般在保存或修改操作之后會redirect到一個結果頁面(不是forward),同時攜帶參數,如操作成功的提示信息。因為是Redirect,Request里的attribute不會傳遞過去。Spring在3.1才提供了這個能力--RedirectAttributes。 反復按F5,操作成功的提示信息也不會再次出來(總共只出現一次),效果很理想。
Java代碼
public String save(@ModelAttribute("group") Group group, RedirectAttributes redirectAttributes) { accountManager.saveGroup(group); redirectAttributes.addFlashAttribute("message", "操作成功"); return "redirect:/account/group/"; }
SeckillResult.java
public class SeckillResult<T>//<T>泛型類
//泛型類型的數據
private T data;
package org.seckill.dto; //<T>泛型類 //所有ajax請求返回類型,封裝json結果 public class SeckillResult<T> { private boolean success; //泛型類型的數據 private T data; private String error; public SeckillResult(boolean success, T data) { super(); this.success = success; this.data = data; } public SeckillResult(boolean success, String error) { super(); this.success = success; this.error = error; } public boolean isSuccess() { return success; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getError() { return error; } public void setError(String error) { this.error = error; } public void setSuccess(boolean success) { this.success = success; } }
SeckillController.java :
package org.seckill.web
package org.seckill.web; import java.util.Date; import java.util.List; import org.seckill.dto.Exposer; import org.seckill.dto.SeckillExecution; import org.seckill.dto.SeckillResult; import org.seckill.entity.Seckill; import org.seckill.enums.SeckillStatEnum; import org.seckill.exception.RepeatKillExeception; import org.seckill.exception.SeckillCloseException; import org.seckill.service.SeckillService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller//類似@Service @component @RequestMapping("/seckill") //url:/模塊/資源/{id}/細分 http://localhost:8080/seckill/seckill/list //去掉@RequestMapping("/seckill")變為http://localhost:8080/seckill/list public class SeckillController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private SeckillService seckillService; @RequestMapping(value="/list",method = RequestMethod.GET) //二級URL public String list(Model model){ //獲取列表頁 List<Seckill> list = seckillService.getSeckillList(); model.addAttribute("list",list); //list.jsp + model = ModelAndView return "list";//spring-web.xml配置了prefix和suffix ->WEB-INF/jsp/list.jsp } // @RequestMapping(value = "/{seckillId}/detail",method = RequestMethod.GET) //也可不寫@PathVariable("seckillId"),默認能識別出,但最好還寫出 /*使用基本類型接收數據還是用包裝類? 使用@PathVariable時注意兩點: 1:參數接收類型使用基本類型 2:不用基本類型時,給defaultValue值 推薦使用包裝類*/ public String detail(@PathVariable("seckillId")Long seckillId,Model model){ //null時,redirect到list.jsp if(seckillId == null){ return "redirect:/seckill/list"; } Seckill seckill = seckillService.getById(seckillId); if(seckill == null){ return "forward:/seckill/list"; } model.addAttribute("seckill",seckill); return "detail"; } /*ajax json RequestMethod.POST直接輸入地址無效 * @ResponseBody 當springmvc看到@ResponseBody的時候會將SeckillResult<Exposer>返回值封裝成json * produces = {"application/json;charset=UTF-8"}解決json中的數據亂碼問題 * */ @RequestMapping(value = "/{seckillId}/exposer", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) @ResponseBody //public void/*TODO*/ exposer(Long seckillId){ public SeckillResult<Exposer> exposer(Long seckillId){ SeckillResult<Exposer> result; try{ Exposer exposer =seckillService.exportSeckillUrl(seckillId); result = new SeckillResult<Exposer>(true,exposer); }catch (Exception e){ logger.error(e.getMessage(),e); result = new SeckillResult<Exposer>(false,e.getMessage()); } return result; } @RequestMapping(value = "/{seckillId}/{md5}/execution", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) public SeckillResult<SeckillExecution> execute(@PathVariable("seckillId")Long seckillId, @PathVariable("md5")String md5, @CookieValue(value = "killPhone",required = false)Long phone){ /*請求的requestpattern中沒有這個cookie killPhone時,springMVC 會報錯,required = false表示killPhone不是必須,就不會報錯,驗證邏輯放入程序*/ //springMVC valid if(phone == null){ return new SeckillResult<SeckillExecution>(false,"未注冊"); } SeckillResult<SeckillExecution> result; try{ SeckillExecution execution = seckillService.executeSeckill(seckillId, phone, md5); return new SeckillResult<SeckillExecution>(true,execution); } catch (SeckillCloseException e) { SeckillExecution execution = new SeckillExecution(seckillId,SeckillStatEnum.REPEAT_KILL); return new SeckillResult<SeckillExecution>(false,execution); } catch (RepeatKillExeception e) { SeckillExecution execution = new SeckillExecution(seckillId,SeckillStatEnum.END); return new SeckillResult<SeckillExecution>(false,execution); }catch (Exception e){ logger.error(e.getMessage(),e); SeckillExecution execution = new SeckillExecution(seckillId,SeckillStatEnum.INNER_ERROR); return new SeckillResult<SeckillExecution>(false,execution); } } @RequestMapping(value = "/time/now", method = RequestMethod.GET) public SeckillResult<Long> time(){ Date now = new Date(); return new SeckillResult(true,now.getTime()); } }
---4 基於bootstrap開發頁面結構---------------------------------------------------------------
BootStrap環境配置:
參照http://www.runoob.com/bootstrap/bootstrap-environment-setup.html
使用HTML模板和Bootstrap CDN版本,使用CDN版本時需要聯網
1.替換模板內的:
<!-- jQuery (Bootstrap 的 JavaScript 插件需要引入 jQuery) -->
<script src="https://code.jquery.com/jquery.js"></script>
<!-- 包括所有已編譯的插件 -->
<script src="js/bootstrap.min.js"></script>
2.主題文件一般不使用,去掉
<!-- 可選的Bootstrap主題文件(一般不使用) -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"></script>
3.新 Bootstrap 核心 CSS 文件與模板內重復,去掉
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
通用部分放入common/head.jsp
common/tag.jsp <!-- 引入標簽庫 -->
使用靜態包含 head.jsp和tag.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- 引入jstl --> <%@include file="common/tag.jsp" %> <!DOCTYPE html> <html> <head> <title>秒殺詳情</title> <%@include file="common/head.jsp" %> </head> <body> <!-- 頁面顯示部分 :推薦放入一個div中--> <div class="container"> </div> </body> <!-- jQuery文件。務必在bootstrap.min.js 之前引入 --> <script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </html>
靜態包含和動態包含的區別
<%@include...%> 靜態包含:會將引用的源代碼原封不動的附加過來,合並過來成一個jsp,對應一個servlet。
<jsp:include...> 動態包含:分別編譯,被包含的jsp獨立編譯成servlet,然后和包涵的jsp頁面編譯生成的靜態文檔html做合並;總是會檢查所包含文件的變化,適合包含動態文件。
靜態包含是被包含的JSP合並到該servlet中。(一個servlet)
動態包含是被包含的JSP先運行servlet,再把運行結果合並到包含的html中(多個servlet)。
使用的class都是bootstrap的css
EL表達式:${}
在配置的時候,注意suffix的值不要寫成*.jsp,否則也會出錯的,以前都是寫成*,寫習慣了。
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
錯誤:
Error 500 HTTPステータス 500 - Internal Server Error Type Exception Report メッセージ Error instantiating servlet class org.springframework.web.servlet.DispatcherServlet 説明 The server encountered an unexpected condition that prevented it from fulfilling the request. 例外 javax.servlet.ServletException: Error instantiating servlet class org.springframework.web.servlet.DispatcherServlet org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.lang.Thread.run(Thread.java:748) 原因 java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1285) org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.lang.Thread.run(Thread.java:748)
解決辦法:
You need to add the "Maven Dependency" in the Deployment Assembly
right click on your project and choose properties.
click on Deployment Assembly.
click add
click on "Java Build Path Entries"
select Maven Dependencies"
click Finish.
Rebuild and deploy again
Note: This is also applicable for non maven project.
@Controller//類似@Service @component @RequestMapping("/seckill") //url:/模塊/資源/{id}/細分 http://localhost:8080/seckill/seckill/list //去掉@RequestMapping("/seckill")變為http://localhost:8080/seckill/list public class SeckillController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private SeckillService seckillService; @RequestMapping(value="/list",method = RequestMethod.GET) //二級URL public String list(Model model){ //獲取列表頁 List<Seckill> list = seckillService.getSeckillList(); model.addAttribute("list",list); //list.jsp + model = ModelAndView return "list";//spring-web.xml配置了prefix和suffix ->WEB-INF/jsp/list.jsp } ... }
頁面:
使用bootstrap,遵守bootstrap的css
WEB-INF/jsp
list.jsp
detail.jsp
common/head.jsp
tag.jsp
list.jsp
<a class="btn btn-info" href="/seckill/seckill/${sk.seckillId}/detail" target="_blank">link</a>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- 引入jstl --> <%@include file="common/tag.jsp" %> <!DOCTYPE html> <html> <head> <title>秒殺列表頁</title> <%@include file="common/head.jsp" %> </head> <body> <!-- 頁面顯示部分 :推薦放入一個div中--> <div class="container"> <div class="panel panel-default"> <div class="panel-heading text-center"> <h2>秒殺列表</h2> </div> <div class="panel-body"> <table class="table table-hover"> <thead> <tr> <th>名稱</th> <th>庫存</th> <th>開始時間</th> <th>結束時間</th> <th>創建時間</th> <th>詳情頁</th> </tr> </thead> <tbody> <!-- 通過標簽迭代:list --> <c:forEach var ="sk" items="${list}"> <tr> <td>${sk.name}</td> <td>${sk.number}</td> <td> <fmt:formatDate value = "${sk.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/> </td> <td> <fmt:formatDate value = "${sk.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/> </td> <td> <fmt:formatDate value = "${sk.createTime}" pattern="yyyy-MM-dd HH:mm:ss"/> </td> <td> <a class="btn btn-info" href="/seckill/seckill/${sk.seckillId}/detail" target="_blank">link</a> </td> </tr> </c:forEach> </tbody> </table> </div> </div> </div> </body> <!-- jQuery文件。務必在bootstrap.min.js 之前引入 --> <script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </html>
detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- 引入jstl --> <%@include file="common/tag.jsp" %> <!DOCTYPE html> <html> <head> <title>秒殺詳情</title> <%@include file="common/head.jsp" %> </head> <body> <!-- 頁面顯示部分 :推薦放入一個div中--> <div class="container"> <div class="panel panel-default"> <div class="panel-heading text-center"> <h2>秒殺詳情</h2> <div class="panel-heading">${seckill.name}</div> </div> <div class="panel-body"> <!-- 開發交互時補全 --> </div> </div> </div> </body> <!-- jQuery文件。務必在bootstrap.min.js 之前引入 --> <script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </html>
common/:共通部分
head.jsp
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 引入 Bootstrap --> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <!-- HTML5 Shim 和 Respond.js 用於讓 IE8 支持 HTML5元素和媒體查詢 --> <!-- 注意: 如果通過 file:// 引入 Respond.js 文件,則該文件無法起效果 --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> <![endif]-->
tag.jsp 引入標簽庫
<!-- 引入標簽庫 --> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
---1-2 學習Restful接口設計---------------------------------------------------------------
---1-2 學習Restful接口設計---------------------------------------------------------------
---1-2 學習Restful接口設計---------------------------------------------------------------
---1-2 學習Restful接口設計---------------------------------------------------------------