时间:2021-07-01 10:21:17 帮助过:101人阅读
修改web.xml,引入SpringMvc的DispatcherServlet:
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="true"> <!--用maven创建的web-app需要修改servlet的版本为3.0--> <servlet> <servlet-name>seckill-dispatchServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--配置springmvc的配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/applicationContext-*.xml</param-value> </init-param> <load-on-startup> 1 </load-on-startup> </servlet> <servlet-mapping> <servlet-name>seckill-dispatchServlet</servlet-name> <!--直接拦截所有请求,不再采用spring2.0的/*或者*.do方式--> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
在这里的话如果你不配置这一段代码的:
<!--配置springmvc的配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/applicationContext-*.xml</param-value> </init-param>
SpringMvc默认就会默认去WEB-INF下查找默认规范的配置文件,像我这里配置的servlet-name是seckill-dispatchServlet的话,则默认会寻找WEB-INF一个名为seckill-dispatchServlet-Servlet.xml的配置文件
SeckillController首先在com.suny下建立包为Controller的包,然后在里面新建一个类SeckillController:
package com.suny.controller;/** * Created by 孙建荣 on 17-5-24.下午10:11 */@Controller@RequestMapping("/seckill")public class SeckillController { private final SeckillService seckillService; @Autowired
public SeckillController(SeckillService seckillService) { this.seckillService = seckillService;
} /** * 进入秒杀列表. * * @param model 模型数据,里面放置有秒杀商品的信息 * @return 秒杀列表详情页面 */
@RequestMapping(value = "/list", method = RequestMethod.GET) public String list(Model model) { List<Seckill> seckillList = seckillService.getSeckillList();
model.addAttribute("list", seckillList); return "list";
} @RequestMapping(value = "/{seckillId}/detail", method = RequestMethod.GET) public String detail(@PathVariable("seckillId") Long seckillId, Model model) { 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";
} /** * 暴露秒杀接口的方法. * * @param seckillId 秒杀商品的id * @return 根据用户秒杀的商品id进行业务逻辑判断,返回不同的json实体结果 */
@RequestMapping(value = "/{seckillId}/exposer", method = RequestMethod.GET) @ResponseBody
public SeckillResult<Exposer> exposer(@PathVariable("seckillId") Long seckillId) { // 查询秒杀商品的结果
SeckillResult<Exposer> result; try { Exposer exposer = seckillService.exportSeckillUrl(seckillId);
result = new SeckillResult<>(true, exposer);
} catch (Exception e) {
e.printStackTrace();
result = new SeckillResult<>(false, e.getMessage());
} return result;
} /** * 用户执行秒杀,在页面点击相应的秒杀连接,进入后获取对应的参数进行判断,返回相对应的json实体结果,前端再进行处理. * * @param seckillId 秒杀的商品,对应的时秒杀的id * @param md5 一个被混淆的md5加密值 * @param userPhone 参与秒杀用户的额手机号码,当做账号密码使用 * @return 参与秒杀的结果,为json数据 */
@RequestMapping(value = "/{seckillId}/{md5}/execution", method = RequestMethod.POST) @ResponseBody
public SeckillResult<SeckillExecution> execute(@PathVariable("seckillId") long seckillId, @PathVariable("md5") String md5, @CookieValue(value = "userPhone", required = false) Long userPhone) { // 如果用户的手机号码为空的说明没有填写手机号码进行秒杀
if (userPhone == null) { return new SeckillResult<>(false, "没有注册");
} // 根据用户的手机号码,秒杀商品的id跟md5进行秒杀商品,没异常就是秒杀成功
try { // 这里换成储存过程
SeckillExecution execution = seckillService.executeSeckill(seckillId, userPhone, md5); return new SeckillResult<>(true, execution);
} catch (RepeatKillException e1) { // 重复秒杀
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStatEnum.REPEAT_KILL); return new SeckillResult<>(false, execution);
} catch (SeckillCloseException e2) { // 秒杀关闭
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStatEnum.END); return new SeckillResult<>(false, execution);
} catch (SeckillException e) { // 不能判断的异常
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStatEnum.INNER_ERROR); return new SeckillResult<>(false, execution);
} // 如果有异常就是秒杀失败
} /** * 获取服务器端时间,防止用户篡改客户端时间提前参与秒杀 * * @return 时间的json数据 */
@RequestMapping(value = "/time/now", method = RequestMethod.GET) @ResponseBody
public SeckillResult<LocalDateTime> time() { LocalDateTime localDateTime = LocalDateTime.now(); return new SeckillResult<>(true, localDateTime);
}
}SeckillResult:
package com.suny.dto;/** * 封装所有的ajax请求返回类型,方便返回json * Created by 孙建荣 on 17-5-24.下午10:18 */public class SeckillResult<T> { private boolean success; private T data; private String error; public SeckillResult() {
} public SeckillResult(boolean success, T data) { this.success = success; this.data = data;
} public SeckillResult(boolean success, String error) { this.success = success; this.error = error;
} public boolean isSuccess() { return success;
} public void setSuccess(boolean success) { this.success = 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;
} @Override
public String toString() { return "SeckillResult{" +
"状态=" + success +
", 数据=" + data +
", 错误消息='" + error + '\'' +
'}';
}
}因为项目的前端页面都是由Bootstrap开发的,所以我们要先去下载Bootstrap或者是使用在线的CDN.
-Bootstrap中文官网
-Bootstrap中文文档 使用在线CDN引入的方法:
<!-- 最新版本的 Bootstrap 核心 CSS 文件 --><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><!-- 可选的 Bootstrap 主题文件(一般不用引入) --><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"><!-- 最新的 Bootstrap 核心 JavaScript 文件 --><script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
文档里面写的很详细,然后我这里是使用离线版本的,方便我们本地调试,避免出现什么别的因素干扰我们:
首先下载JQuery,因为Bootstrap就是依赖JQuery的
然后下载Bootstrap
然后下载一个倒计时插件jquery.countdown.min.js -再下载一个操作Cookie插件jquery.cookie.min.js 如图放置:
首先编写一个公共的头部jsp文件,位于WEB-INF下common中的head.jsp
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/plugins/bootstrap-3.3.0/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/plugins/bootstrap-3.3.0/css/bootstrap-theme.min.css" type="text/css">然后编写一个公共的jstl标签库文件,位于WEB-INF下common中的tag.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
编写列表页面,位于WEB-INF下common中的list.jsp
<%@page contentType="text/html; charset=UTF-8" language="java" %>
<%@include file="common/tag.jsp" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>秒杀列表</title>
<%@include file="common/head.jsp" %>
</head>
<body>
<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>
<td>名称</td>
<td>库存</td>
<td>开始时间</td>
<td>结束时间</td>
<td>创建时间</td>
<td>详情页</td>
</tr>
</thead>
<tbody>
<c:forEach items="${list}" var="sk">
<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/${sk.seckillId}/detail" target="_blank">详情</a></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
</body>
<script src="${pageContext.request.contextPath}/resources/plugins/jquery.js"></script>
<script src="${pageContext.request.contextPath}/resources/plugins/bootstrap-3.3.0/js/bootstrap.min.js"></script>
</html>编写列表页面,位于WEB-INF下common中的detail.jsp,秒杀详情页面
<%-- Created by IntelliJ IDEA. User: jianrongsun Date: 17-5-25 Time: 下午5:03 To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@include file="common/tag.jsp" %>
<html>
<head>
<title>秒杀商品详情页面</title>
<%@include file="common/head.jsp" %>
</head>
<body>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h1>${seckill.name}</h1>
</div>
<div class="panel-body">
<h2 class="text-danger">
<span class="glyphicon glyphicon-time"></span>
<span class="glyphicon" id="seckill-box"></span>
</h2>
</div>
</div>
</div>
<div id="killPhoneModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title text-center">
<span class="glyphicon glyphicon-phone"></span>秒杀电话:
</h3>
</div>
</div>
<div class="modal-body">
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<input type="text" name="killPhone" id="killPhoneKey" placeholder="填写手机号码" class="form-control">
</div>
</div>
</div>
<div class="modal-footer">
<span id="killPhoneMessage" class="glyphicon"></span>
<button type="button" id="killPhoneBtn" class="btn btn-success">
<span class="glyphicon glyphicon-phone"></span>
提交
</button>
</div>
</div>
</div>
</body>
<script src="${pageContext.request.contextPath}/resources/plugins/jquery.js"></script>
<script src="${pageContext.request.contextPath}/resources/plugins/bootstrap-3.3.0/js/bootstrap.min.js"></script>
<script src="${pageContext.request.contextPath}/resources/plugins/jquery.cookie.min.js"></script>
<script src="${pageContext.request.contextPath}/resources/plugins/jquery.countdown.min.js"></script>
<script src="${pageContext.request.contextPath}/resources/script/seckill.js"></script>
<script type="text/javascript"> $(function () { var startTimeVal = "${seckill.startTime.toLocalDate()} " + seckill.cloneZero("${seckill.startTime.toLocalTime()}"); var endTimeVal = "${seckill.endTime.toLocalDate()} " + seckill.cloneZero("${seckill.endTime.toLocalTime()}"); console.log("startTimeVal========" + startTimeVal); console.log("endTimeVal========" + endTimeVal); // 传入参数 seckill.detail.init({ seckillId:${seckill.seckillId}, startTime: startTimeVal, endTime: endTimeVal }) })</script>
</html>然后把项目运行一下我们又会碰到一个错误就是jstl中的fmt标签格式化时间只能格式化java.Util.Date类型的日期跟时间,而在我们这里我么使用了java8的LocalDateTIme,所以解析时间会出异常,这时我们应该想到自己去实现jstl标签来自定义解析这个时间日期 自定义标签步骤如下:
在/WEB-INF创建目录 tags
然后创建一个文件 localDateTime.tag 在tags目录下
localData.tag用来格式化日期
localDataTime.tag用来格式化日期跟时间的组合,也就是数据库中的Timestamp类型 -然后在localDataTime.tag中写自己自定义的格式化流程
<%--格式化java8的LocalDatime,解决jstl不支持java8时间的问题--%><%@ tag body-content="empty" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %><%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %><%-- 这里是定义页面使用标签中的属性设置,<tags:localDataTime dateTime="${sk.createTIme}"/> --%><%@ attribute name="dateTime" required="true" type="java.time.LocalDateTime" %><%@ attribute name="pattern" required="false" type="java.lang.String" %><%--首选判断日期时间转换规则是否存在,不存在给出默认的规则--%><c:if test="${empty pattern}">
<c:set var="pattern" value="yyyy-MM-dd HH:mm:ss"/>
</c:if>
<c:set var="datetime" value="${dateTime}"/> <%-- 获取jsp页面传入的【 日期时间 】,格式为【 2017-5-26T13:59:12 】 --%><c:set var="time" value="${fn:substringAfter(datetime, 'T')}"/> <%-- 获取页面传过来的【时间T】后面的 【 时:分:秒 】的值 --%><c:set var="timeLength" value="${fn:length(time)}"/> <%-- 获取页面传来的 【 时:分:秒 的长度 】 --%><c:set var="generalLength" value="${fn:length('123456')}"/> <%-- 这里定义了一个【Integer】类型的值,值为字符串 【123456 】的长度 --%><c:set var="cloneZero" value=":00"/> <%-- 这里设置一个值为【String】的字符串, --%><%-- 当 时:分:秒 不足6位的时候就说明缺少秒,我们给它自动补充 :00 --%><c:if test="${timeLength lt generalLength}">
<c:set var="datetimeCloneZero"
value="${datetime}${cloneZero}"/> <%-- 拼接页面传过来的 【 时:分 】 ,补充一个【秒数】,EL中 + 为相加,非拼接字符串 --%>
<c:set var="cleandDateTime"
value="${fn:rep