Java秒杀系统及优化---(1)

 

 

一、项目框架搭建

  • SpringBoot环境搭建
  • 集成Thymeleaf,Result结果封装
  • 集成Mybatis+Druid
  • 集成Jedis+通用缓存Key封装

 

1、springboot项目框架搭建

Java秒杀系统及优化---(1)_第1张图片

1.1)下载后,解压并导入IDEA中,再添加其他需要的依赖。

1.2)springboot与其他组件的整合非常方便,只需要在src/main/resources目录下的application.properties文件中添加相应配置即可。

1.3)我们先新建几个常用的包domain、dao、service、controller...

Java秒杀系统及优化---(1)_第2张图片

2、集成Thymeleaf,封装rest接口的输出结果。

  • 第一步:添加Thymeleaf的依赖(这个之前已经添加好了)
  • 第二步:配置Thymeleaf(在application.properties中添加配置即可)
  • 配置完成后,我们写一个简单的测试,看配置是否成功!

2.1)首先在resources/templates目录下新建一个hello.html文件





    hello
    



2.2)然后在controller目录下新建一个DemoController.java文件

@Controller
public class DemoController {

    @GetMapping("/thymeleaf")
    public String thymeleaf(Model model){
        model.addAttribute("name", "wyq");
        return "hello";
    }
}

然而启动时出现问题,百度后,通过降低springboot版本,才解决,之前使用的是2.1.2,改为1.5.9版本。

再次启动:

Java秒杀系统及优化---(1)_第3张图片

2.3)打开浏览器,访问8080端口下的/thymeleaf.html(要添加.html的后缀,这是在配置文件中自己配置的)

显示了我们之前添加的内容,表明springboot整合thymeleaf成功。

2.4)另外说一点:作为一个controller,它里面的方法总共分为两大类:一类是rest api json输出;另一类是页面。

json输出时,一般来说,我们的客户端和服务端会做一个接口的约定,例如,我们的输出结果是一个json结构,里面有这么几个属性:code代表错误码,msg代表错误信息,data代表成功时的数据。

{
    "code":XXX
    "msg":XXX
    "data":XXX
}

那么,做这样的封装有什么好处呢?假如我们约定0代表成功,那么客户端只要得到code是0,就可以从data中取数据;假如我们约定500100表示session失效,那么客户端只要看到500100,就可以直接跳转到登陆页面。所以说,这种方式,无论是对客户端还是对服务端来说,都是非常方便的。

那么,我们就先对接口的输出结果做一个类似的封装

public class Result  {
    private int code;
    private String msg;
    /**
     * 因为不知道data具体是哪种类型,所以写成泛型
     */
    private T data;
...

但是,这样在写代码时还是有点儿问题,在controller中,有一个方法,就需要new Result(XXX,XXX,XXX)

    @GetMapping("/hello")
    @ResponseBody
    public Result hello(){
        return new Result(0, "success", "hello wyq!");
    }

    @GetMapping("/helloError")
    @ResponseBody
    public Result helloError(){
        return new Result(500102, "XXX");
    }

    ...

这样显然不合适,controller不止一个,controller中的方法也不止一个,这样要写太多的new Result(XXX,XXX,XXX)。

那么,我们可不可以用一个常量类来解决这问题?把他们都写到常量类中可不可以?当然可以,但是还是有问题:因为我们这里的code和msg是一对,所以说,最好的办法,就是把他们都放在一块。

我们想要实现什么效果呢?成功时Result.success(data);失败时Result.error(CodeMsg xxx);CodeMsg是个对象,封装了code和msg的对应信息。可以将所有的CodeMsg都写在这个类中,后期维护也很方便。

public class CodeMsg {
    private int code;
    private String msg;

......

那么,我们来修改一下这个Result类,添加几个方法

    /**
     * 这里改为private,因为我们不希望用户通过构造函数来生成Result对象
     * 而是通过我们封装好的方法来生成对象
     * @param data
     */
    private Result(T data) {
        this.code = 0;
        this.msg = "success";
        this.data = data;
    }

    public Result(CodeMsg cm) {
        if(cm == null) {
            return;
        }

        this.code = cm.getCode();
        this.msg = cm.getMsg();
    }

    /**
     * 成功时调用
     * @param data
     * @param 
     * @return
     */
    public static  Result success(T data) {
        return new Result(data);
    }

    /**
     * 失败时调用
     * @param cm
     * @param 
     * @return
     */
    public static  Result error(CodeMsg cm) {
        return new Result(cm);
    }

到此为止,封装完成。我们再来测试一下:

    @GetMapping("/hello")
    @ResponseBody
    public Result hello(){
        //成功时只需要传递数据
        return Result.success("hello wyq!");
        //return new Result(0, "success", "hello wyq!");
    }

    @GetMapping("/helloError")
    @ResponseBody
    public Result helloError(){
        //失败时只需要传递CodeMsg
        return Result.error(CodeMsg.SERVER_ERROR);
        //return new Result(500102, "XXX");
    }

效果(由于没写对应的页面,所以访问时不添加后缀.html):

Java秒杀系统及优化---(1)_第4张图片Java秒杀系统及优化---(1)_第5张图片

好了,rest api json输出就说这么多,我们来看一下controller中的另一类方法:页面

这里就是集成thymeleaf做页面模板,上面的hello:wyq的例子就是,这里就不多说了。

3、集成Mybatis

  • 第一步:添加mybatis的依赖,还要添加mysql驱动的依赖和druid数据库连接池的依赖
  • 第二步:配置mybatis,mysql,druid
  • 配置完成后,在数据库中新建一个user表来对刚才的配置进行测试:id设置为自增的

Java秒杀系统及优化---(1)_第6张图片

3.1)新建实体类User

public class User {
    private int id;
    private String name;

...

3.2)新建对应的UserDao接口

@Mapper
public interface UserDao {
    /**
     * 通过@Param定义参数id,然后再使用#{} 来引用这个参数
     * @param id
     * @return
     */
    @Select("select * from user where id = #{id}")
    public User getById(@Param("id") int id);

}

由于比较简单,这里不再做单元测试。

@Service
public class UserService {
    @Autowired
    UserDao userDao;

    public User getById(int id) {
        return userDao.getById(id);
    }
}
    @GetMapping("/db/get")
    @ResponseBody
    public Result doGet(){
        User user = userService.getById(1);
        return Result.success(user);
    }

3.3)DemoController中添加doGet方法,往数据库中插入一条数据

启动工程,测试:

Java秒杀系统及优化---(1)_第7张图片

到这里,其实已经测试成功,mybatis配置完成。

3.4)下面再测试一下事务

插入一条id为2的记录,再插入一条id为1的记录

在UserDao中添加

	@Insert("insert into user(id, name) values(#{id}, #{name})")
	public int insert(User user);

UserService添加

	@Transactional
	public boolean tx() {
		User u1= new User();
		u1.setId(2);
		u1.setName("2222");
		userDao.insert(u1);
		
		User u2= new User();
		u2.setId(1);
		u2.setName("11111");
		userDao.insert(u2);
		
		return true;
	}

同在一个事务中,第二条插入失败,会使第一条插入成功的也回滚。

DemoController中添加

	@GetMapping("/db/tx")
	@ResponseBody
	public Result dbTx(){
		userService.tx();
		return Result.success(true);
	}

测试:

Java秒杀系统及优化---(1)_第8张图片

肯定会出错,下面看一下数据库,id为2的记录有没有插入进去

没有插入。

去掉事务注解后再次测试

Java秒杀系统及优化---(1)_第9张图片

好的,依然会有错误,查看数据库数据

我们可以看到id为2的数据插入成功!至此,springboot与mybatis的集成完毕!!!

4、集成Redis

  • 第一步:添加Jedis依赖,添加Fastjson依赖
  • 第二步:添加配置

4.1)为什么使用fastjson呢?用来把java对象转化为字符串,存到redis中

因为对象序列化最快,效率最高的就是google的Protobuf,但是google的Protobuf的一个缺点是:它序列化之后是不可读的,是一种二进制格式,但是用fastjson之后,他是一个json格式,明文可读,这样方便我们查看,他们效率差多少呢?大概是差了一倍,如果Protobuf用了1毫秒,则fastjson用2毫秒,为了方便,我们使用fastjson。

4.2)封装redis操作

1)在redis包中新建一个RedisConfig类,用来加载配置文件中有关redis的配置信息:

2)新建一个RedisPoolFactory类,利用RedisConfig的对象,将JedisPool注入到spring容器中:

3)再新建一个RedisService类,利用RedisPool的对象完成对redis的具体操作(这里是自己写对jedis的操作,主要是为了练习,所以没有使用springboot整合的redis)

【以上3个类,就不列出了,后面会给出所有代码。】

4.3)这里还要注意的是,对redis中的key的设计,在原来的key的基础上添加前缀,来更好的区分各种key

4.4)对redis配置完以后,我们在DemoController中做个测试:

    @GetMapping("/redis/get")
    @ResponseBody
    public Result redisGet(){
        User user = redisService.get(UserKey.getById, "" + 1, User.class);
        return Result.success(user);
    }

    @GetMapping("/redis/set")
    @ResponseBody
    public Result redisSet(){
        User user = new User();
        user.setId(1);
        user.setName("哈哈");
        redisService.set(UserKey.getById, ""+ 1, user); //UserKey:id1
        return Result.success(true);
    }

先启动redis,通过客户端查看其中的值,没有任何key:

再运行程序,调用set方法:

Java秒杀系统及优化---(1)_第10张图片

再次查看(这里为了方便,直接用图形化客户端进行查看),redis中有值:

再调用get方法:

Java秒杀系统及优化---(1)_第11张图片

到此为止,redis这里基本完成了。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Web框架)