博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用IDEA整合SSM框架
阅读量:6871 次
发布时间:2019-06-26

本文共 23717 字,大约阅读时间需要 79 分钟。

文章所用例子参考相关课程。

使用IDEA创建一个maven的webapp项目,建好相应的项目结构。

目录结构

  • main

    • java:java源码

      • com.dct.seckillDemo:包名,一般为groupId+artifactId

        • dao:Data Access Object,数据访问对象,主要数据库操作相关方法。
        • dto:主要是自定义的pojo,用于service层与web层之间的数据传输
        • entity:实体包,是简单的java对象(pojo),与数据库中的表对应。
        • service:主要的业务逻辑层
        • web:即控制器层,接受请求并调用服务,返回数据和视图。
    • resources

      • mapper:与mybatis数据库操作相关的xml文件
      • spring:spring相关配置文件
    • webapp

      • resources:项目的静态资源,如js css images等。
      • WEB-INF:外部浏览器无法访问,只有内部才能访问
  • test

    • java:java测试相关代码
    • resources:测试所需资源文件

然后导入项目依赖的jar包

pom.xml

4.0.0
com.dct
seckillDemo
war
1.0-SNAPSHOT
seckillDemo Maven Webapp
http://maven.apache.org
junit
junit
4.11
test
org.slf4j
slf4j-api
1.7.12
ch.qos.logback
logback-core
1.1.1
ch.qos.logback
logback-classic
1.1.1
mysql
mysql-connector-java
5.1.35
runtime
c3p0
c3p0
0.9.1.2
org.mybatis
mybatis
3.3.0
org.mybatis
mybatis-spring
1.2.3
taglibs
standard
1.1.2
jstl
jstl
1.2
com.fasterxml.jackson.core
jackson-databind
2.5.4
javax.servlet
javax.servlet-api
3.1.0
org.springframework
spring-core
4.1.7.RELEASE
org.springframework
spring-beans
4.1.7.RELEASE
org.springframework
spring-context
4.1.7.RELEASE
org.springframework
spring-jdbc
4.1.7.RELEASE
org.springframework
spring-tx
4.1.7.RELEASE
org.springframework
spring-web
4.1.7.RELEASE
org.springframework
spring-webmvc
4.1.7.RELEASE
org.springframework
spring-test
4.1.7.RELEASE
seckillDemo

下面开始进行整合SSM,首进行mybatis和spring的整合。

在resources下新建jdbc.properties和mybatis-config.xml文件。

jdbc.properties(数据库连接相关参数)

jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf-8jdbc.username=rootjdbc.password=root

mybatis-config.xml(mybatis全局属性的配置)

然后在spring包下新建spring-dao.xml文件,进行spring和mybatis的整合配置。

spring-dao.xml

在spring包下新建spring-service.xml文件,配置service层。

spring-service.xml

在spring包下新建spring-web.xml文件,配置控制器层。

spring-web.xml

配置web.xml文件

web.xml

seckill-dispatcher
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring/spring-*.xml
seckill-dispatcher
/
字符集过滤器
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
字符集编码
encoding
UTF-8
encodingFilter
/*
index.jsp

目前为止,SSM整合工作就已经完成,项目目录结构如下。

目录结构


SSM框架应用示例--秒杀系统

首先新建数据库及相应的数据表,在main下新建一个sql包,然后新建一个schema.sql文件

schema.sql

-- 数据库初始化脚本-- 创建数据库CREATE DATABASE seckill;-- 使用数据库,只有INNODb支持事务use seckill;CREATE TABLE seckill(  `seckill_id` BIGINT NOT NUll AUTO_INCREMENT COMMENT '商品库存ID',  `name` VARCHAR(120) NOT NULL COMMENT '商品名称',  `number` int NOT NULL COMMENT '库存数量',  `start_time` TIMESTAMP  NOT NULL COMMENT '秒杀开始时间',  `end_time`   TIMESTAMP   NOT NULL COMMENT '秒杀结束时间',  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',  PRIMARY KEY (seckill_id),  key idx_start_time(start_time),  key idx_end_time(end_time),  key idx_create_time(create_time))ENGINE=INNODB AUTO_INCREMENT=10000 DEFAULT CHARSET=utf8 COMMENT='秒杀库存表';-- 初始化数据INSERT into seckill(name,number,start_time,end_time)VALUES  ('1000元秒杀iphone6',100,'2016-01-01 00:00:00','2016-01-02 00:00:00'),  ('800元秒杀ipad',200,'2016-01-01 00:00:00','2016-01-02 00:00:00'),  ('6600元秒杀mac book pro',300,'2016-01-01 00:00:00','2016-01-02 00:00:00'),  ('7000元秒杀iMac',400,'2016-01-01 00:00:00','2016-01-02 00:00:00');-- 秒杀成功明细表-- 用户登录认证相关信息(简化为手机号)CREATE TABLE success_killed(  `seckill_id` BIGINT NOT NULL COMMENT '秒杀商品ID',  `user_phone` BIGINT NOT NULL COMMENT '用户手机号',  `state` TINYINT NOT NULL DEFAULT -1 COMMENT '状态标识:-1:无效 0:成功 1:已付款 2:已发货',  `create_time` TIMESTAMP NOT NULL COMMENT '创建时间',  PRIMARY KEY(seckill_id,user_phone),/*联合主键*/  KEY idx_create_time(create_time))ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='秒杀成功明细表';  -- SHOW CREATE TABLE seckill;#显示表的创建信息

dao层开发

在entity包中新建两个实体类,属性分别与数据表一一对应

Seckill.java

public class Seckill{    private long seckillId;    private String name;    private int number;    //该注解处理日期的格式化    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")    private Date startTime;    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")    private Date endTime;    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")    private Date createTime;   public Seckill(){   }    public Seckill(String name, int number, Date startTime, Date endTime) {        this.name = name;        this.number = number;        this.startTime = startTime;        this.endTime = endTime;    }    public long getSeckillId() {        return seckillId;    }    public void setSeckillId(long seckillId) {        this.seckillId = seckillId;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getNumber() {        return number;    }    public void setNumber(int number) {        this.number = number;    }    public Date getStartTime() {        return startTime;    }    public void setStartTime(Date startTime) {        this.startTime = startTime;    }    public Date getEndTime() {        return endTime;    }    public void setEndTime(Date endTime) {        this.endTime = endTime;    }    public Date getCreateTime() {        return createTime;    }    public void setCreateTime(Date createTime) {        this.createTime = createTime;    }    @Override    public String toString() {        return "Seckill{" +                "seckillId=" + seckillId +                ", name='" + name + '\'' +                ", number=" + number +                ", startTime=" + startTime +                ", endTime=" + endTime +                ", createTime=" + createTime +                '}';    }}

SuccessKilled.java

public class SuccessKilled{    private long seckillId;    private long userPhone;    private short state;    private Date createTime;    //省略getter,setter和toString方法 }

在dao包下新建两个接口,定义数据库操作相关方法

seckillDao.java

@Repositorypublic interface SeckillDao{    /**     * 减库存     * @param seckillId     * @param killTime     * @return 如果影响行数>1,表示更新库存的记录行数     */    int reduceNumber(@Param("seckillId") long seckillId, @Param("killTime") Date killTime);    /**     * 根据id查询秒杀的商品信息     * @param seckillId     * @return     */    Seckill queryById(long seckillId);    /**     * 根据偏移量查询秒杀商品列表     * @param offset     * @param limit     * @return     */    List
queryAll(@Param("offset") int offset, @Param("limit") int limit); // 添加秒杀物品 boolean addItem(Seckill seckill); // 删除秒杀物品 boolean deleteById(long seckillId); // 更新秒杀物品 boolean updateItem(Seckill seckill); }

SuccessKilledDao.java

@Repositorypublic interface SuccessKilledDao {    /**     * 插入购买明细,可过滤重复     * @param seckillId     * @param userPhone     * @return插入的行数     */    int insertSuccessKilled(@Param("seckillId") long seckillId, @Param("userPhone") long userPhone);    /**     * 根据秒杀商品的id查询明细SuccessKilled对象(该对象携带了Seckill秒杀产品对象)     * @param seckillId     * @return     */    SuccessKilled queryByIdWithSeckill(@Param("seckillId") long seckillId, @Param("userPhone") long userPhone);}

在resources包下的mapper保重创建xml文件,实现dao包接口中的方法。

SeckillDao.xml

UPDATE seckill SET number = number-1 WHERE seckill_id=#{seckillId} AND start_time #{killTime} AND end_time >= #{killTime} AND number > 0;
INSERT INTO seckill(name,number,start_time,end_time) VALUES (#{name},#{number},#{startTime},#{endTime})
DELETE FROM seckill WHERE seckill_id=#{seckillId}
UPDATE seckill set name=#{name},number=#{number},start_time=#{startTime},end_time=#{endTime} WHERE seckill_id=#{seckillId}

SuccessKilledDao.xml

INSERT ignore INTO success_killed(seckill_id,user_phone,state) VALUES (#{seckillId},#{userPhone},0)

完成了dao层开发,接下来对到dao方法进行测试。点击我们要测试的类,快捷键ctrl+shift+t,创建新的测试,选择测试的路径及所要测试的方法。

图片描述
图片描述
SeckillDaoTest.java

/** * Created by codingBoy on 16/11/27. * 配置spring和junit整合,这样junit在启动时就会加载springIOC容器 */@RunWith(SpringJUnit4ClassRunner.class)//告诉junit spring的配置文件@ContextConfiguration({"classpath:spring/spring-dao.xml"})public class SeckillDaoTest {    //注入Dao实现类依赖    @Resource    private SeckillDao seckillDao;    @Test    public void reduceNumber() throws Exception {        long seckillId=10000;        Date date=new Date();        int updateCount=seckillDao.reduceNumber(seckillId,date);        System.out.println(updateCount);    }    @Test    public void queryById() throws Exception {        long seckillId=10000;        Seckill seckill=seckillDao.queryById(seckillId);        System.out.println(seckill.getName());        System.out.println(seckill);    }    @Test    public void queryAll() throws Exception {        List
seckills=seckillDao.queryAll(0,100); for (Seckill seckill : seckills) { System.out.println(seckill); } } @Test public void addItem() throws Exception { Seckill seckill = new Seckill("222",300,new Date(),new Date()); seckillDao.addItem(seckill); } @Test public void deleteById() throws Exception { seckillDao.deleteById(10011); } @Test public void updateItem() throws Exception { Seckill seckill = seckillDao.queryById(10018); seckill.setNumber(500); seckillDao.updateItem(seckill); }}

dao层开发过程中的注意点

  1. 主要xml文件与dao接口中的方法一一对应
  2. 对于与数据表对应的实体类,mybatis提供了自动生成的工具,详见

对所有的dao包中的方法进行测试后,就可进入service层方法的开发。

service层为主要的业务逻辑层,也是最复杂的部分,一般在service下新建一个接口,然后在impl包下放接口的实现类。
SeckillService.java

/**业务接口:站在使用者(程序员)的角度设计接口 * 三个方面:1.方法定义粒度,方法定义的要非常清楚2.参数,要越简练越好 * 3.返回类型(return 类型一定要友好/或者return异常,我们允许的异常) * Created by codingBoy on 16/11/27. */public interface SeckillService {    /**     * 查询全部的秒杀记录     * @return     */    List
getSeckillList(); /** *查询单个秒杀记录 * @param seckillId * @return */ Seckill getById(long seckillId); //再往下,是我们最重要的行为的一些接口 /** * 在秒杀开启时输出秒杀接口的地址,否则输出系统时间和秒杀时间 * @param seckillId */ Exposer exportSeckillUrl(long seckillId); /** * 执行秒杀操作,有可能失败,有可能成功,所以要抛出我们允许的异常 * @param seckillId * @param userPhone * @param md5 * @return */ SeckillExecution executeSeckill(long seckillId, long userPhone, String md5) throws SeckillException,RepeatKillException,SeckillCloseException; void addItem(Seckill seckill); void deleteItemById(long seckillId); void updateItemById(Seckill seckill);}

SeckillServiceImpl.java

@Servicepublic class SeckillServiceImpl implements SeckillService{    //日志对象    private Logger logger= LoggerFactory.getLogger(this.getClass());    //加入一个混淆字符串(秒杀接口)的salt,为了我避免用户猜出我们的md5值,值任意给,越复杂越好    private final String salt="shsdssljdd'l.";    //注入Service依赖    @Autowired //@Resource    private SeckillDao seckillDao;    @Autowired //@Resource    private SuccessKilledDao successKilledDao;    public List
getSeckillList() { return seckillDao.queryAll(0,100); } public Seckill getById(long seckillId) { return seckillDao.queryById(seckillId); } public Exposer exportSeckillUrl(long seckillId) { Seckill seckill = seckillDao.queryById(seckillId); if (seckill == null){ return new Exposer(false,seckillId); } //若是秒杀未开启 Date startTime=seckill.getStartTime(); Date endTime=seckill.getEndTime(); //系统当前时间 Date nowTime=new Date(); if (startTime.getTime()>nowTime.getTime() || endTime.getTime()

以上代码中用到了dto、enums、exception包中自定义的类。

dto包下三个类

//省略getter,setter和toString方法public class Exposer {    //是否开启秒杀    private boolean exposed;    //加密措施    private String md5;    private long seckillId;    //系统当前时间(毫秒)    private long now;    //秒杀的开启时间    private long start;    //秒杀的结束时间    private long end;    public Exposer(boolean exposed, String md5, long seckillId) {        this.exposed = exposed;        this.md5 = md5;        this.seckillId = seckillId;    }    public Exposer(boolean exposed, long seckillId,long now, long start, long end) {        this.exposed = exposed;        this.seckillId=seckillId;        this.now = now;        this.start = start;        this.end = end;    }    public Exposer(boolean exposed, long seckillId) {        this.exposed = exposed;        this.seckillId = seckillId;    }  }
//省略getter,setter和toString方法public class SeckillExecution {    private long seckillId;    //秒杀执行结果的状态    private int state;    //状态的明文标识    private String stateInfo;    //当秒杀成功时,需要传递秒杀成功的对象回去    private SuccessKilled successKilled;    //秒杀成功返回所有信息    public SeckillExecution(long seckillId, SeckillStatEnum statEnum, SuccessKilled successKilled) {        this.seckillId = seckillId;        this.state = statEnum.getState();        this.stateInfo = statEnum.getInfo();        this.successKilled = successKilled;    }    //秒杀失败    public SeckillExecution(long seckillId, SeckillStatEnum statEnum) {        this.seckillId = seckillId;        this.state = statEnum.getState();        this.stateInfo = statEnum.getInfo();    }  }
//将所有的ajax请求返回类型,全部封装成json数据public class SeckillResult
{ //请求是否成功 private boolean success; private T data; private String error; public SeckillResult(boolean success, T data) { this.success = success; this.data = data; } public SeckillResult(boolean success, String error) { this.success = success; this.error = error; } }

新建enums存放枚举类型

public enum SeckillStatEnum {    SUCCESS(1,"秒杀成功"),    END(0,"秒杀结束"),    REPEAT_KILL(-1,"重复秒杀"),    INNER_ERROR(-2,"系统异常"),    DATE_REWRITE(-3,"数据篡改");    private int state;    private String info;    SeckillStatEnum(int state, String info) {        this.state = state;        this.info = info;    }    public int getState() {        return state;    }    public String getInfo() {        return info;    }    public static SeckillStatEnum stateOf(int index)    {        for (SeckillStatEnum state : values())        {            if (state.getState()==index)            {                return state;            }        }        return null;    }}

新建exception存放自定义的异常类

public class RepeatKillException extends SeckillException {    public RepeatKillException(String message) {        super(message);    }    public RepeatKillException(String message, Throwable cause) {        super(message, cause);    }}
public class SeckillException extends RuntimeException {    public SeckillException(String message) {        super(message);    }    public SeckillException(String message, Throwable cause) {        super(message, cause);    }}
public class SeckillCloseException extends SeckillException{    public SeckillCloseException(String message) {        super(message);    }    public SeckillCloseException(String message, Throwable cause) {        super(message, cause);    }}

完成service层,进行测试


控制层开发

在web包下新建控制类

SeckillController.java

/** /seckill/list    获取列表* /seckill/{seckillId}/detail   物品详情* /seckill/{seckillId}/exposer   获取物品秒杀地址* /seckill/{seckillId}/{md5}/execution   执行物品秒杀** /seckill/add  get获取添加页面* /seckill/add  post向数据库中添加记录* /seckill/{seckillId}/update  get获取更新页面* /seckill/update  post更新数据* /seckill//{seckillId}delete  删除数据* */@Controller@RequestMapping("/seckill")//url:模块/资源/{}/细分public class SeckillController{    @Autowired    private SeckillService seckillService;    @RequestMapping(value = "/list",method = RequestMethod.GET)    public String list(Model model)    {        //list.jsp+mode=ModelAndView        //获取列表页        List
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 = "/add",method = {RequestMethod.GET}) public String addItemUI(){ return "add"; } @RequestMapping(value = "/add",method = {RequestMethod.POST}) public String addItemInfo(Seckill seckill){ seckillService.addItem(seckill); return "redirect:/seckill/list"; } @RequestMapping(value = "/{sk.seckillId}/delete",method = {RequestMethod.GET}) public String deleteItem(@PathVariable("sk.seckillId") Long seckillId){ seckillService.deleteItemById(seckillId); return "redirect:/seckill/list"; } @RequestMapping(value = "/{sk.seckillId}/update",method = {RequestMethod.GET}) public String updateItemUI(@PathVariable("sk.seckillId") Long seckillId,Model model){ Seckill seckill = seckillService.getById(seckillId); model.addAttribute("item",seckill); return "update"; } @RequestMapping(value = "/update",method = {RequestMethod.POST}) public String updateItem(Seckill seckill){ seckillService.updateItemById(seckill); return "redirect:/seckill/list"; } //ajax ,json暴露秒杀接口的方法 @RequestMapping(value = "/{seckillId}/exposer", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"}) @ResponseBody public SeckillResult
exposer(@PathVariable("seckillId") Long seckillId) { SeckillResult
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; } @RequestMapping(value = "/{seckillId}/{md5}/execution", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) @ResponseBody public SeckillResult
execute(@PathVariable("seckillId") Long seckillId, @PathVariable("md5") String md5, @CookieValue(value = "userPhone",required = false) Long userPhone) { if (userPhone==null) { return new SeckillResult
(false,"未注册"); } SeckillResult
result; 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
(true,execution); }catch (SeckillCloseException e2) { SeckillExecution execution=new SeckillExecution(seckillId, SeckillStatEnum.END); return new SeckillResult
(true,execution); } catch (Exception e) { SeckillExecution execution=new SeckillExecution(seckillId, SeckillStatEnum.INNER_ERROR); return new SeckillResult
(true,execution); } } //获取系统时间 @RequestMapping(value = "/time/now",method = RequestMethod.GET) @ResponseBody public SeckillResult
time() { Date now=new Date(); return new SeckillResult
(true,now.getTime()); }}

web层开发过程中的注意点

  1. 注意类级别与方法级别路径映射的区别
  2. 返回页面和返回json类型数据不同的注解方式
  3. 方法中参数的获取

目前为止,秒杀系统后端服务全部完成,前端相关代码就不在此贴出来,全部代码见

转载地址:http://kqpfl.baihongyu.com/

你可能感兴趣的文章
“李开复”危机
查看>>
libvirt 网络
查看>>
每日英语:Poor Chinese Schools Tell Students: Bring Your Own Desks
查看>>
HDU 4268
查看>>
IE9中FCKEditor弹出层不好使的解决方法
查看>>
JBOSS java.lang.NoSuchFieldError: TRACE
查看>>
轻量级的jQuery表单验证插件 - HAPPY.js
查看>>
JavaScript 生成Guid
查看>>
jQuery+PHP+MySQL简单无限级联实现
查看>>
互联网创业的准备——版本控制与上线
查看>>
网站推广优化教程100条(SEO,网站关键字优化,怎么优化网站,如何优化网站关键字)...
查看>>
用c++和python写GUI程序(python嵌入方式)
查看>>
Code sample – socket client thread in Python
查看>>
2013年8月3日第31周六
查看>>
Android使用隐藏api的方法(使用被@hide的api)
查看>>
Robert Penner's Easing Functions
查看>>
Parallel for loops in .NET C# z
查看>>
mysql alter修改字段的长度 类型sql语句
查看>>
第24周二
查看>>
[轉載]史上最强php生成pdf文件,html转pdf文件方法
查看>>