秒殺系統Web實踐——01框架搭建Spring Boot+Mybatis +Redis(Jedis)

第一章項目框架搭建

項目github:https://github.com/LCYang-1/-

主要任務

1.Spring Boot環境搭建

2.集成Thymeleaf , Result結果封裝

3.集成Mybatis + Druid

4.集成Jedis+ Redis安裝+通用緩存Key封裝

5.測試


 


 

1.Spring Boot環境搭建

目前選取這些依賴,後期遇到什麼,再添加就行了(記性不好!!一步一步來吧)

2.集成Thymeleaf , Result結果封裝

編輯application.properties配置文件

Result結果封裝

    private int code;        //響應碼
    private String msg;      //提示
    private T data;          //內容

詳細封裝請看gitbut

3.集成Mybatis + Druid

添加依賴

 <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>

         <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>

添加配置

#mybatis
mybatis.type-aliases-package=com.lcy.miaosha.pojo
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=3000
mybatis.mapper-locations=classpath:com/lcy/miaosha/dao/*.xml

#數據源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/miaosha?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=1234
        
# druid
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.filters=stat
spring.datasource.maxActive=2
spring.datasource.initialSize=1
spring.datasource.maxWait=60000
spring.datasource.minIdle=1
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=select 'x'
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxOpenPreparedStatements=20

4.集成Jedis+ Redis安裝+通用緩存Key封裝

Redis安裝

請參考https://www.runoob.com/redis/redis-install.html

添加依賴

依賴原生Jedis;添加Fastjson,序列化後爲json,方便查看。

        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.1.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>

在application.properties設置配置參數

這裏我使用的是自定義的配置參數

#redis
redis.host=***.***.***.***
redis.port=6379
#連接超時時間
redis.timeout=3
redis.password=123456
#連接池配置
#最大連接數
redis.poolMaxTotal=10
#最大空閒連接數
redis.poolMaxIdle=10
#最大等待連接數
redis.poolMaxWait=3

所以我們要寫一個類來獲取配置參數信息

@Component
@ConfigurationProperties(prefix = "redis")
public class RedisConfig {

    private String host;
    private int port;
    private int timeout;//秒
    private String password;
    private int poolMaxTotal;
    private int poolMaxIdle;
    private int  poolMaxWait;//秒

    //set/get方法
    /**
    *別忘添加
    */
}

編寫JedisPoolFactory類來配置JedisPool資源連接池

@Service
public class JedisPoolFactory {

    @Autowired
    RedisConfig redisConfig;

    @Bean
    public JedisPool JedisPoolFactory(){

        System.out.println(redisConfig.toString());
        JedisPoolConfig poolConfig=new JedisPoolConfig();
        poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
        poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
        poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait()*1000);
        JedisPool jp=new JedisPool(poolConfig,redisConfig.getHost(),redisConfig.getPort()
                ,redisConfig.getTimeout()*1000,redisConfig.getPassword(),0);
        return jp;
    }
}

通用緩存Key封裝

爲防止我們使用Redis時Key值重複給予不同類型含義的Value,我們在此對通用緩存Key封裝

一個接口

public interface KeyPrefix {

    public int expireSeconds();

    public String getPrefix();

}

一個抽象類

public abstract class BasePrefix implements KeyPrefix {

    private int expireSeconds;

    private String prefix;

    public BasePrefix( String prefix) {
        this(0,prefix);
    }

    public BasePrefix(int expireSeconds, String prefix) {
        this.expireSeconds = expireSeconds;
        this.prefix = prefix;
    }

    @Override
    public int expireSeconds() {//0代表永不過期
        return expireSeconds;
    }

    @Override
    public String getPrefix() {
        String classname = getClass().getSimpleName();
        return classname+":"+prefix;
    }
}

RedisService類的編寫

分別有get、set、exists、incr、decr。

@Service
public class RedisService {

    @Autowired
    JedisPool jedisPool;

    /**
     * 獲取單個對象
     * @param prefix
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T get(KeyPrefix prefix,String key,Class<T> clazz){
        Jedis jedis =null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey =prefix.getPrefix()+key;
            String str = jedis.get(realKey);
            T t=stringToBean(str,clazz);
            return t;

        }finally {
            returnToPool(jedis);
        }

    }

    /**
     * 設置對象
     * @param prefix
     * @param key
     * @param value
     * @param <T>
     * @return
     */
    public <T> boolean set(KeyPrefix prefix,String key,T value){
        Jedis jedis =null;
        try {
            jedis = jedisPool.getResource();
            String str=beanToString(value);
            if (str==null||str.length()<=0)
                return false;
            //生成真正的key
            String realKey =prefix.getPrefix()+key;
            int seconds=prefix.expireSeconds();
            if (seconds<=0){
                jedis.set(realKey,str);
            } else {
                jedis.setex(realKey,seconds,str);
            }
            jedis.set(realKey, str);
            return true;

        }finally {
            returnToPool(jedis);
        }

    }

    /**
     * 判斷是否存在
     * @param prefix
     * @param key
     * @param <T>
     * @return
     */
    public <T> boolean exists(KeyPrefix prefix,String key){
        Jedis jedis =null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey =prefix.getPrefix()+key;
            return jedis.exists(realKey);

        }finally {
            returnToPool(jedis);
        }

    }

    /**
     * 增加值
     * @param prefix
     * @param key
     * @param <T>
     * @return
     */
    public <T> Long incr(KeyPrefix prefix,String key){
        Jedis jedis =null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey =prefix.getPrefix()+key;
            return jedis.incr(realKey);

        }finally {
            returnToPool(jedis);
        }

    }

    /**
     * 減少值
     * @param prefix
     * @param key
     * @param <T>
     * @return
     */
    public <T> Long decr(KeyPrefix prefix,String key){
        Jedis jedis =null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey =prefix.getPrefix()+key;
            return jedis.decr(realKey);

        }finally {
            returnToPool(jedis);
        }

    }


    private <T> String beanToString(T value) {
        if (value==null)
            return null;
        Class<?> aClass = value.getClass();
        if (aClass==int.class||aClass==Integer.class){
            return ""+value;
        }else if (aClass==String.class){
            return (String) value;
        }else if (aClass==long.class||aClass==Long.class){
            return ""+value;
        }else {
            return JSON.toJSONString(value);
        }
    }

    private <T> T stringToBean(String str,Class<T> aClass) {
        if (str==null||str.length()<=0||aClass==null)
            return null;


        if (aClass==int.class||aClass==Integer.class){
            return (T)Integer.valueOf(str);
        }else if (aClass==String.class){
            return (T)str;
        }else if (aClass==long.class||aClass==Long.class){
            return (T)Long.valueOf(str);
        }else {
            return JSON.toJavaObject(JSON.parseObject(str),aClass);
        }
    }

    private void returnToPool(Jedis jedis) {
        if (jedis!=null){
            jedis.close();
        }
    }


}

 


5.測試

前提條件,數據庫中有一個可用的表

對應的User類

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

對應的一個UserDao

@Mapper
public interface UserDao {

    @Select("select * from user where id=#{id}")
    public User getById(@Param("id") int id);


}

當然還有UserService

@Service
public class UserService {

    @Autowired
    UserDao userDao;

    public User getById(int id){
        return userDao.getById(id);
    }
}

我們還要實現一個UserKey來繼承BasePrefix

public class UserKey extends BasePrefix {
    public UserKey(String prefix) {
        super(prefix);
    }
    public static UserKey getById=new UserKey("id");
    public static UserKey getByName=new UserKey("name");
}

現在我們就可以進行測試了,我們通過Controll類來進行測試

@Controller
@RequestMapping("/demo")
public class SampleController {

    @Autowired
    RedisService redisService;

    @Autowired
    UserService userService;

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

    @RequestMapping("/db/get")
    @ResponseBody
    public String dbGet(){
        User user=userService.getById(1);
        return user.toString();
    }

    @RequestMapping("/redis/get")
    @ResponseBody
    public String redisGet(){
        User v1=redisService.get(UserKey.getById,""+1,User.class);
        return v1.toString();
    }

    @RequestMapping("/redis/set")
    @ResponseBody
    public boolean redisSet(){
        User user = new User(1, "1111");
        boolean b = redisService.set(UserKey.getById, "" + 1, user);

        return b;
    }
}

看到第一個方法返回一個“hello”字符串,並且沒有 @ResponseBody註解,我們就要編輯相應的hello.html頁面

他的位置對應在classpath:/templates/

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>hello</title>
    <meta http-equiv="Content-Type " content="text/html;charset=UTF-8"/>
</head>
<body>
<p th:text="'hello:'+${name}"></p>
</body>
</html>

啓動項目

圖片說明Thymeleaf一切正常

圖片說明Mybatis+Druid+Result結果封裝正常圖片說明redis服務正常


到此爲止第一章的內容就算結束了!!!!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章