SSM实战——秒杀系统之Web层Restful url设计、SpringMVC整合、页面设计
一:Spring整合SpringMVC
1:编写web.xml,配置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"> <servlet>
<servlet-name>seckill-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指明配置文件路径 -->
<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>
2:在resource/spring下,新建spring-web.xml,整合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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
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-4.1.xsd">
<!-- 1:开启注解模式 -->
<mvc:annotation-driven/>
<!-- 2:配置静态资源默认处理器-->
<mvc:default-servlet-handler/>
<!-- 3:配置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>
<!-- 4:配置扫描controller所在包 -->
<context:component-scan base-package="org.myseckill.web"/>
</beans>
二:SpringMVC controller开发并实现restful url设计
RestFul架构见博客:http://kb.cnblogs.com/page/512047/
Restful url 格式:/模块/资源/{id}/细分
1:在org.myseckill包下新建web包,用于存放所有controller。
2:web包下新建一个controller:SeckillController
package org.myseckill.web; import java.util.Date;
import java.util.List; import org.junit.runners.Parameterized.Parameter;
import org.myseckill.entity.Seckill;
import org.myseckill.exception.RepeatKillException;
import org.myseckill.service.SeckillService;
import org.myseckill.dto.Exposer;
import org.myseckill.dto.SeckillExecution;
import org.myseckill.dto.SeckillResult;
import org.myseckill.enums.SeckillStateEnum;
import org.myseckill.exception.*;
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//注册该bean
@RequestMapping("/seckill")//映射项目模块
public class SeckillController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private SeckillService seckillService;
//列表页请求
@RequestMapping(value="/list",method=RequestMethod.GET)
public String list(Model model){//model用于存放数据,字符串用于控制跳转
List<Seckill> list=seckillService.getSeckillList();
model.addAttribute("list",list);
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";
} @RequestMapping(value="/{seckillId}/exposer",method=RequestMethod.POST,produces={"application/json;charset=UTF-8"})
@ResponseBody//把返回数据转换成JSON格式,绑定到响应中
//Ajax方法,返回JSON数据
public SeckillResult<Exposer> exposer(@PathVariable 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"})
@ResponseBody
public SeckillResult<SeckillExecution> execute(@PathVariable Long seckillId, @PathVariable String md5,@CookieValue(value = "killPhone", required = false) Long userPhone) {
if(userPhone==null){
return new SeckillResult<SeckillExecution>(false, "未注册");
}
try {
SeckillExecution execution=seckillService.executeSeckill(seckillId, userPhone, md5);
return new SeckillResult<SeckillExecution>(true, execution);
} catch (RepeatKillException e) {
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.REPEAT_KILL);
return new SeckillResult<SeckillExecution>(true,execution);
} catch (SeckillException e) {
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.END);
return new SeckillResult<SeckillExecution>(true,execution);
} catch (Exception e){
SeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.INNER_ERROR);
return new SeckillResult<SeckillExecution>(false,execution);
}
} @RequestMapping(value="/time/now",method=RequestMethod.GET)
@ResponseBody
public SeckillResult<Long> time(){
Date now = new Date();
return new SeckillResult<Long>(true,now.getTime());
}
}
3:新建一个dto:SeckillResult,封装controller的处理结果
package org.seckill.dto; //所有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 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;
}
}
三:页面开发
在WEB-INF下新建文件夹jsp,用于存放所有页面。
1:jsp文件夹下新建common文件夹,用于存放一些共用的jsp页面头/尾。
head.jsp:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入 Bootstrap -->
<link
href="http://cdn.static.runoob.com/libs/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]-->
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<base href="<%=basePath %>">
tag.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
2:创建页面jsp
列表页list.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@include file="common/tag.jsp"%>
<!DOCTYPE html>
<html>
<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>
<th>名称</th>
<th>库存</th>
<th>开始时间</th>
<th>结束时间</th>
<th>创建时间</th>
<th>详情页</th>
</tr>
</thead>
<tbody>
<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/${sk.seckillId}/detail" target="_blank">link</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div> </body>
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="http://cdn.static.runoob.com/libs/jquery/2.1.1/jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/js/bootstrap.min.js"></script> </html></th>
2:详情页detail.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<title>秒杀详情页</title>
<%@include file="common/head.jsp"%>
</head>
<body>
<div class="container">
<div class="panel panel-default text-center">
<div class="panel-heading">
<h1>${seckill.name}</h1>
</div>
<div class="panel-body">
<h2 class="text-danger">
<!-- 显示time图标 -->
<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 class="modal-body">
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<input type="text" name="killPhone" id="killPhoneKey"
placeholder="填手机号^o^" 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>
Submit
</button>
</div>
</div>
</div>
</div>
</body>
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="http://cdn.static.runoob.com/libs/jquery/2.1.1/jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- 使用cdn获取公共js http://www.bootcdn.cn -->
<!-- jQuery cookie操作插件 -->
<script src="http://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<!-- jQuery countDown倒计时插件 -->
<script src="http://cdn.bootcss.com/jquery.countdown/2.2.0/jquery.countdown.min.js"></script>
<!-- 开始编写交互逻辑 -->
<script src="/MySeckill/resources/script/seckill.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//使用EL表达式传入参数
seckill.detail.init({
'seckillId' : '${seckill.seckillId}',
'startTime' : '${seckill.startTime.time}',//毫秒
'endTime' : '${seckill.endTime.time}' });
});
</script>
</html>
3:在WebRoot下新建一个文件夹resources,用于存放一些共用的资源,如js、images等。
resource下新建一个文件夹script,新建一个js文件 seckill.js,用于书写交互函数:
//存放主要交互逻辑js代码
//javascript模块化.json类型
var seckill={
//封装秒杀相关ajax的url
URL:{
now : function(){
return "seckill/time/now";
},
exposer : function(seckillId){
return 'seckill/'+seckillId+'/exposer';
},
execution : function(seckillId,md5){
return 'seckill/'+seckillId+'/'+md5+'/execution';
}
},
handlerSeckill:function(seckillId, node){
//获取秒杀地址,控制显示逻辑 执行秒杀
node.hide().html('<button class="btn btn-primary btn-lg" id="killBtn">开始秒杀</button>');
$.post(seckill.URL.exposer(seckillId),{},function(result){
//在回调函数中执行交互流程
if(result && result['success']){
var exposer = result['data'];
if(exposer['exposed']){
//开启秒杀
var md5 = exposer['md5'];
var killUrl = seckill.URL.execution(seckillId,md5);
console.log("killUrl:"+killUrl);
//绑定一次点击事件
$('#killBtn').one('click',function(){
//执行秒杀请求的操作
//1.先禁用按钮
$(this).addClass('disabled');
//2.发送秒杀请求
$.post(killUrl,{},function(result){
if(result && result['success']){
var killResult = result['data'];
var state = killResult['state'];
var stateInfo = killResult['stateInfo'];
//3.显示秒杀结果
node.html('<span class="label label-success">'+stateInfo+'</span>');
}
});
});
node.show();
}else{
//未开始秒杀
var now = exposer['now'];
var start = exposer['start'];
var end = exposer['end'];
//重新计算计时逻辑
seckill.countdown(seckillId,now,start,end);
}
}else{
console.log('result:'+result);
}
});
},
//验证手机号
validatePhone:function(phone){
if(phone && phone.length==11 && !isNaN(phone)){//isNaN不是数字
return true;
} else {
return false;
}
},
countdown:function(seckillId, nowTime, startTime, endTime){
var seckillBox = $('#seckill-box');
if(nowTime > endTime){
seckillBox.html('秒杀结束!');
} else if(nowTime < startTime){
//秒杀未开始,倒计时
var killTime = new Date(startTime-0 + 1000);
seckillBox.countdown(killTime,function(event){
//时间格式
var format = event.strftime('秒杀倒计时: %D天 %H时 %M分 %S秒');
seckillBox.html(format);
/*时间完成后回调函数*/
}).on('finish.countdown',function(){
//获取秒杀地址,控制显示逻辑 执行秒杀
seckill.handlerSeckill(seckillId, seckillBox);
});
}else{
//秒杀开始
seckill.handlerSeckill(seckillId, seckillBox);
}
},
//详情页秒杀逻辑
detail:{
//详情页初始化
init : function(params){
//用户手机验证和登陆,计时交互
//在cookie中查找手机号
var killPhone = $.cookie('killPhone');
var startTime = params['startTime'];
var endTime = params['endTime'];
var seckillId = params['seckillId'];
//验证手机号
if(!seckill.validatePhone(killPhone)){
//绑定phone
var killPhoneModal = $('#killPhoneModal');
killPhoneModal.modal({
show:true,//显示弹出层
backdrop:'static',//禁止位置关闭
keyboard:false//关闭键盘事件
});
$('#killPhoneBtn').click(function(){
var inputPhone = $('#killPhoneKey').val();
if(seckill.validatePhone(inputPhone)){
//电话写入cookie
$.cookie('killPhone',inputPhone,{expires:7,path:'/seckill'});
//刷新页面
window.location.reload();
} else {
$('#killPhoneMessage').hide().html('<label class="label label-danger">手机号错误!</label>').show(300);
}
});
}
//已经登陆
//计时交互
$.get(seckill.URL.now(),{},function(result){
if(result && result['success']){
var nowTime = result['data'];
seckill.countdown(seckillId, nowTime, startTime, endTime);
} else {
console.log('result:'+result);
}
});
}
}
}
4:部署测试记录
提示DispatcherServlet找不到,或者配置文件找不到,首先检查部署到tomcat的目录下有无对应文件。
如果没有,则检查是否Myeclipse中的关于项目编译文件输出目录与部署文件拉取目录不一致导致出错。
一般,Maven项目都会把项目编译文件输出到target目录下,而我们需要的是WebRoot/WEB-INF/classes目录,所以需要修改。
1)右键项目,Buildpath——configer buildPath
2)选择 source 选项卡
3)修改output folder:
4)左侧,打开部署选项配置
5)修改拉取路径
SSM实战——秒杀系统之Web层Restful url设计、SpringMVC整合、页面设计的更多相关文章
- SSM实战——秒杀系统之Service层接口设计与实现、Spring托管、声明式事务
一:Service层接口设计 准备工作:新建三个包:service包.exception包.dto包,分别用来存放业务接口.自定义异常类.dto类. 1:定义接口 package org.myseck ...
- SSM实战——秒杀系统之DAO层实体定义、接口设计、mybatis映射文件编写、整合Spring与Mybatis
一:DAO实体编码 1:首先,在src目录下,新建org.myseckill.entity包,用于存放实体类: 2:实体类设计 根据前面创建的数据库表以及映射关系,创建实体类. 表一:秒杀商品表 对应 ...
- SSM实战——秒杀系统之创建项目、管理依赖、设计数据库
注:本项目使用Myeclipse开发. 一:项目创建 1:使用Myeclipse创建一个web project,命名为MySeckill,并转换为Maven项目. 2:创建项目文件目录如下: 上面四个 ...
- SSM实战——秒杀系统前言
项目来源:慕课网http://www.imooc.com/u/2145618/courses?sort=publish 项目开发流程:整合SSM框架——项目需求分析与实现——解决高并发优化 所用技术: ...
- SSM实战——秒杀系统之高并发优化
一:高并发点 高并发出现在秒杀详情页,主要可能出现高并发问题的地方有:秒杀地址暴露.执行秒杀操作. 二:静态资源访问(页面)优化——CDN CDN,内容分发网络.我们把静态的资源(html/css/j ...
- 03 整合IDEA+Maven+SSM框架的高并发的商品秒杀项目之web层
Github:https://github.com/nnngu 项目源代码:https://github.com/nnngu/nguSeckill 前端交互流程设计 对于一个系统,需要产品经理.前端工 ...
- SSM实现秒杀系统案例
---------------------------------------------------------------------------------------------[版权申明:本 ...
- Java高并发秒杀API之web层
第1章 设计Restful接口 1.1前端交互流程设计 1.2 学习Restful接口设计 什么是Restful?它就是一种优雅的URI表述方式,用来设计我们资源的访问URL.通过这个URL的设计,我 ...
- SSM之秒杀系统
利用idea搭建SSM框架,主要利用Maven仓库下载相应的jar包,以下是相关的pom.xml <project xmlns="http://maven.apache.org/POM ...
随机推荐
- Eclipse断点调试(DBG)Android应用
1.添加断点 双击左侧边框便可添加断点,右击也能添加断点. 2.进入调试模式 点击虫子,然后选择工程运行,快捷键为单击F11 ,如果是正常运行就是Ctrl+F11 3.单步调试+跳到下一个断点 运行到 ...
- js混淆加密,通过混淆Js代码让别人(很难)无法还原
js混淆加密,通过混淆Js代码让别人(很难)无法还原 使用js的混淆加密,其目的是为了保护我们的前端代码逻辑,对应一些搞技术吃饭的公司来说,为了防止被竞争对手抓取或使用自己的代码,就会考虑如何加密 ...
- caffe 生成检测框并绘图
Step 1 使用训练好的模型检测图片: build/examples/ssd/ssd_detect.bin models/VGGNet/VOC0712/SSD_300x300/deploy.prot ...
- 脚本中export不起作用的原因分析
#!bin/bash export PATH=$PATH:/usr/lib/java/jre export PATH=$PATH:/usr/lib/java/bin ---path 结果发现直接运行. ...
- glyphicons-halflings-regular.woff2:1 Failed to load resource: the server responded with a status of 404 (Not Found)解决Web部署 svg/woff/woff2字体 404错误
问题:最近在IIS上部署web项目的时候,发现浏览器总是报找不到woff.woff2字体的错误.导致浏览器加载字体报404错误,白白消耗了100-200毫秒的加载时间. 原因:因为服务器IIS不认SV ...
- CentOS下httpd下php 连接mysql 本机可以,外网报错Could not connect: Can't connect to MySQL server on '127.0.0.1' (13)2003 原因解析
php代码很简单: $server="127.0.0.1"; println("Begin"); $link = mysql_connect($server,& ...
- iOS:创建带logol的二维码
//二维码生成 实质: 把字符串转变为 图片 // 需要 coreImage框架, 已经包含在了 UIKit框架里面 //MARK: 二维码中间内置图片,可以是公司logo + (UIImage *) ...
- libxml2 使用教程【转】
https://blog.csdn.net/zhoudaxia/article/details/8565731# 本文整理自官方使用教程http://xmlsoft.org/tutorial/inde ...
- ASP.NET文件下载各种方式比较:对性能的影响、对大文件的支持、对断点续传和多线程下载的支持
asp.net里提供了多种方式,从服务器端向客户端写文件流,实现客户端下载文件.这种技术在做防下载系统时比较有用处.主些技术主要有:WriteFile.TransmitFile和BinaryWrite ...
- c#以POST方式模拟提交表单
这是我一年前写的一个用C#模拟以POST方式提交表单的代码,现在记录在下面,以免忘记咯.那时候刚学C#~忽忽..很生疏..代码看上去也很幼稚 臃肿不堪 #region 内容添加函数(Contentin ...