
前端: Thymeleaf,Bootstrap,JQuery
后端: SpringBoot,JSR303,MyBatis
中间件: RabbitMQ,Redis,Druid
**应对大并发: **
父工程pom.xml
4.0.0 com.hmx miaosha 1.0-SNAPSHOT miaosha01 pom org.springframework.boot 2.5.0 spring-boot-starter-parent 8 8
子工程pom.xml
org.apache.commons commons-lang3 org.springframework.boot spring-boot-starter-web org.projectlombok lombok
创建启动类,三层
1.2 集成Thymeleaf,Result结果封装org.springframework.boot spring-boot-starter-thymeleaf
application.properties
# 允许thymeleaf使用缓存 spring.thymeleaf.cache=true # 是否为web框架启动thymeleaf视图解析 spring.thymeleaf.enabled=true # 写入 HTTP 响应的 Content-Type 值。 spring.thymeleaf.servlet.content-type=text/html # 模板文件编码 spring.thymeleaf.encoding=UTF-8 # 要应用于模板的模板模式 spring.thymeleaf.mode=HTML5 # 在构建 URL 时预先添加到查看名称的前缀。 spring.thymeleaf.prefix=classpath:/templates/ # 在构建 URL 时预先添加到查看名称的后缀。 spring.thymeleaf.suffix=.html
Result.java
@Data public class Result{ private int code; private String msg; private T data; private Result(T data) { this.code = CodeMsg.SUCCESS.getCode(); this.msg = CodeMsg.SUCCESS.getMsg(); this.data = data; } private Result(CodeMsg cm) { if (cm == null) { return; } this.code = CodeMsg.SERVER_ERROR.getCode(); this.msg = CodeMsg.SERVER_ERROR.getMsg(); } public static Result success(T data) { return new Result (data); } public static Result fail(CodeMsg cm) { return new Result (cm); } }
CodeMsg.java
public enum CodeMsg {
//通用异常
SUCCESS(0,"success"),
SERVER_ERROR(500100, "服务端异常");
//登录模块 5002XX
//商品模块 5003XX
//订单模块 5004XX
//秒杀模块 5005XX
private int code;
private String msg;
private CodeMsg(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
1.3 集成Mybatis+Druid
导入依赖
mybatis相关配置com.alibaba druid 1.2.6 mysql mysql-connector-java 8.0.25 com.baomidou mybatis-plus-boot-starter 3.4.3
# mybatis # 搜索类别名的包 mybatis-plus.type-aliases-package=com.hmx.miaosha.domain # 下划线转成驼峰 mybatis-plus.configuration.map-underscore-to-camel-case=true # 为驱动程序设置一个提示,以控制返回结果的获取大小。此参数值可以被查询设置覆盖。 mybatis-plus.configuration.default-fetch-size=100 # 设置驱动程序等待数据库响应的秒数。 mybatis-plus.configuration.default-statement-timeout=3000 # Mapper xml配置文件的位置 mybatis-plus.mapper-locations=classpath:com/hmx/miaosha/mapper}" = systemd ] #then # echo "This systems seems to use systemd." # echo "Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry!" # exit 1 #fi
10. 查看系统服务列表
chkconfig --list | grep redis
systemctl start redis_6379集成Redis
redis.clients jedis
com.alibaba fastjson 1.2.75
# redis spring.redis.host=192.168.174.128 spring.redis.port=6379 spring.redis.database=0 spring.redis.timeout=3 spring.redis.password=123456 spring.redis.jedis.pool.max-active=10 # 最大空闲 10个 spring.redis.jedis.pool.max-idle=10 spring.redis.jedis.pool.max-wait=3通用缓存Key封装
RedisConfig.java
@Component
@ConfigurationProperties(prefix = "spring.redis")
@Data
public class RedisConfig {
private String host;
private int port = 6379;
//秒
private int timeout;
// 使用几号库
private int database = 0;
private String password;
private int maxActive = 10;
private int maxIdle = 10;
//秒
private int maxWait = 3;
}
RedisService.java
@Service
public class RedisService {
@Autowired
private JedisPool jedisPool;
public Boolean set(String key, T value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String str = beanToString(value);
jedis.set(key, str);
return true;
} finally {
returnToPool(jedis);
}
}
public T get(String key, Class clazz) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String str = jedis.get(key);
T t = stringToBean(str,clazz);
return t;
} finally {
returnToPool(jedis);
}
}
private String beanToString(T value) {
if (value == null) {
return null;
}
Class> clazz = value.getClass();
if (clazz == Integer.class) {
return "" + value;
} else if (clazz == String.class) {
return (String) value;
} else if (clazz == Long.class) {
return "" + value;
} else {
return JSON.toJSONString(value);
}
}
private T stringToBean(String str, Class clazz) {
if (StringUtils.isBlank(str) || clazz == null) {
return null;
}
if (clazz == Integer.class) {
return (T)Integer.valueOf(str);
} else if (clazz == String.class) {
return (T)str;
} else if (clazz == Long.class) {
return (T) Long.valueOf(str);
} else {
return JSON.parseObject(str,clazz);
}
}
private void returnToPool(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
}
JedisPoolFactory.java
@Service
public class RedisPoolFactory {
@Autowired
private RedisConfig redisConfig;
@Bean
public JedisPool jedisPoolFactory() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(redisConfig.getMaxIdle());
poolConfig.setMaxTotal(redisConfig.getMaxActive());
poolConfig.setMaxWaitMillis(redisConfig.getMaxWait() * 1000L);
JedisPool jp = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(), redisConfig.getTimeout() * 1000, redisConfig.getPassword(), redisConfig.getDatabase());
return jp;
}
}
注意: 本来把RedisPoolFactory中的内容放在RedisService中的,启动会报循环依赖,因为RedisService依赖JedisPool,JedisPool依赖RedisService中的RedisConfig
测试@Controller
@RequestMapping("/demo")
public class DemoController {
@Autowired
private UserService userService;
@Autowired
private RedisService redisService;
@RequestMapping("/redis/get")
@ResponseBody
public Result redisGet() {
return Result.success(redisService.get("key1", Long.class));
}
@RequestMapping("/redis/set")
@ResponseBody
public Result redisSet() {
return Result.success(redisService.set("key2", "hello hmx"));
}
@RequestMapping("/db/tx")
@ResponseBody
public Result tx() {
return userService.tx();
}
@RequestMapping("/thymeleaf")
public String thymeleaf(Model model) {
model.addAttribute("name", "HMX");
return "hello";
}
@ResponseBody
@RequestMapping("/hello")
public Result hello() {
return Result.success("hello springboot");
}
@ResponseBody
@RequestMapping("/error")
public Result error() {
return Result.fail(CodeMsg.SERVER_ERROR);
}
}
完善并优化redis相关类
在redis中set key时可能会出现key被覆盖的操作,所以我们使用前缀来避免这个情况,不同的模块使用不同的前缀
KeyPrefix.java
public interface KeyPrefix {
int expireSeconds();
String getPrefix();
}
basePrefix.java
public abstract class basePrefix implements KeyPrefix{
private int expireSeconds;
private String prefix;
public basePrefix(String prefix) {
this(0, prefix);
}
public basePrefix() {
}
public basePrefix(int expireSeconds, String prefix) {
this.expireSeconds = expireSeconds;
this.prefix = prefix;
}
@Override
public int expireSeconds() {
return expireSeconds;
}
@Override
public String getPrefix() {
return getClass().getSimpleName() + ":" + prefix;
}
}
UserKey.java
public class UserKey extends basePrefix{
private UserKey(String prefix) {
super(prefix);
}
public static UserKey getById = new UserKey("id");
public static UserKey getByName = new UserKey("name");
}
RedisService.java
@Service
public class RedisService {
@Autowired
private JedisPool jedisPool;
public Boolean set(KeyPrefix prefix, String key, T value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix() + key;
String str = beanToString(value);
int seconds = prefix.expireSeconds();
if (seconds <= 0) {
jedis.set(realKey, str);
} else {
jedis.setex(realKey, (long)seconds, str);
}
return true;
} finally {
returnToPool(jedis);
}
}
public T get(KeyPrefix prefix, String key, Class 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);
}
}
public 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);
}
}
public 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);
}
}
public 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 String beanToString(T value) {
if (value == null) {
return null;
}
Class> clazz = value.getClass();
if (clazz == Integer.class) {
return "" + value;
} else if (clazz == String.class) {
return (String) value;
} else if (clazz == Long.class) {
return "" + value;
} else {
return JSON.toJSONString(value);
}
}
private T stringToBean(String str, Class clazz) {
if (StringUtils.isBlank(str) || clazz == null) {
return null;
}
if (clazz == Integer.class) {
return (T)Integer.valueOf(str);
} else if (clazz == String.class) {
return (T)str;
} else if (clazz == Long.class) {
return (T) Long.valueOf(str);
} else {
return JSON.parseObject(str,clazz);
}
}
private void returnToPool(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
}
DemoController.java
@Controller
@RequestMapping("/demo")
public class DemoController {
@Autowired
private UserService userService;
@Autowired
private RedisService redisService;
@RequestMapping("/redis/get")
@ResponseBody
public Result redisGet() {
return Result.success(redisService.get(UserKey.getById, "2", User.class));
}
@RequestMapping("/redis/set")
@ResponseBody
public Result redisSet() {
User user = new User();
user.setId(2);
user.setName("hmx2");
return Result.success(redisService.set(UserKey.getById, "2", user));
}
@RequestMapping("/db/tx")
@ResponseBody
public Result tx() {
return userService.tx();
}
@RequestMapping("/thymeleaf")
public String thymeleaf(Model model) {
model.addAttribute("name", "HMX");
return "hello";
}
@ResponseBody
@RequestMapping("/hello")
public Result hello() {
return Result.success("hello springboot");
}
@ResponseBody
@RequestMapping("/error")
public Result error() {
return Result.fail(CodeMsg.SERVER_ERROR);
}
}