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 ...
随机推荐
- ios之CABasicAnimation
博主:最近iOS开发中用到CoreAnimation的framework来做动画效果,虽然以前也用过,但一直没有系统学习过,今天看到一篇非常详细的博文(虽然是日语,但真的写的很好),在此翻译出来供大家 ...
- Orchard模块开发全接触2:新建 ProductPart
一:创建 Part 1:项目引用 Orchard.Framework: 2:创建 Models 文件夹: 3:在 Models 文件夹下创建类 ProductPartRecord,如下: public ...
- ImportError: No module named model_libs
在运行ssd时遇到这个问题 实际是python接口的路径不对,使用echo $$PYTHONPATH 弹出当前python路径,发现是caffe自己的python接口,采用 export PYTHO ...
- 【转】windows下mongodb安装与使用整理
转自 :http://www.cnblogs.com/lecaf/archive/2013/08/23/mongodb.html 一.首先安装mongodb 1.下载地址:http://www.mon ...
- 【Android归纳】开发中应该注意的事项
1.子线程中不能更新界面,更新界面必须在主线程中进行 2.Fragment注意的事项: a) Activity调用Fragment中的方法 b) Thread或者Handler调用Fragment ...
- JAVA 是否会发生内存泄露(转)
原文链接: JAVA 是否会发生内存泄露 几次面试,面试官都问到了这个问题,于是搜集了答案.总结出虽然java自身有垃圾回收机制,但是很多情况下还是发生内存泄露的. java导致内存泄露的原因很明确: ...
- ASP.NET MVC:WebPageRenderingBase.cs
ylbtech-funcation-Utility: ASP.NET MVC:WebPageRenderingBase.cs 提供用于呈现使用 Razor 视图引擎的页的方法和属性. 1.A,WebP ...
- pytorch之dataloader深入剖析
PyTorch学习笔记(6)——DataLoader源代码剖析 - dataloader本质是一个可迭代对象,使用iter()访问,不能使用next()访问: - 使用iter(dataloader) ...
- AOP AspectJ 字节码 语法 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- js时间戳怎么转成日期格式
原文地址:http://www.sufeinet.com/thread-1500-1-1.html js时间戳怎么转成日期格式这个在主群里有朋友§☆釺哖蟲...o问js时间戳怎么转成日期格式 ,他的问 ...