[TOC]
Preface
Sometimes we need to start some projects quickly, but the environment is often tossed for a long time, so we have a reusable quick-build tutorial. docker
simply an artifact in this regard. Docker is an open source application container engine that allows developers to package them. The application and dependent packages of the software are transferred to a portable image, and then released to any popular Linux or Windows operating system machine, which can also be virtualized.
The prerequisites this tutorial is based on:
- The machine has been installed and configured
JDK1.8
, and the environment variables have been configured successfully Maven
has been configured,IDEA
items using defaultMaven
also configure success- The local machine is installed
Docker
- By the way, I use
navicat
as a database visualization tool
project address: ├── src :源代码
| ├── main
| | ├── java
| | | ├── com.aphysia.springbootdemo
| | | | ├── config:配置
| | | | | ├── RedisConfig:redis配置
| | | | ├── constant:常量
| | | | | ├── RedisConfig:redis常量
| | | | ├── controller:控制器
| | | | ├── mapper:数据库操作接口
| | | | ├── model:实体类
| | | | ├── service:逻辑处理层,包括接口以及实现类
| | | | | ├── impl:接口实现类
| | | | ├──util:工具类
| | | | | ├── RedisUtil:redis工具类
| | | | ├──SpringdemoApplication:启动类
| | ├── resource
| | | ├── mapper 数据库操作sql
| | | ├── application.yml:全局配置类
| | | ├── user.sql: 初始化mysql
| ├── test: 测试类
├── pom.xml :项目maven依赖关系
The overall catalog is as follows: Query the latest mirror of Pull the latest version Start You can check whether the installation is successful Query the mirror image of Pull the latest mirror of Let's start the container of You can see that in Mainly to create the database and test the data table used, the statement to initialize the database: The initialization data is as follows: In IDEA, File --> New --> Project --> Spring Initializr (choose JDK 8): Click Select <img src="https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211121213058.png" style="zoom:70%;" /> Global configuration file Start class Database Corresponding First define an interface class Interface implementation class Add a test layer Start the project and enter the link: http://localhost:8081/getUserList, you can get all Let's update the age of all users, call Visit How do I know that There is another way, download At this point, a [Profile of the author] :Build the project
1. docker install and start mysql and redis
1.1 Install mysql
mysql
docker search mysql
mysql
docker pull mysql:latest
mysql
, user name root
, password 123456
docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
docker ps
% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
574d30f17868 mysql "docker-entrypoint.s…" 14 months ago Up 2 days 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql-test
1.2 Install redis
redis
docker search redis
redis
% docker pull redis:latest
latest: Pulling from library/redis
eff15d958d66: Pull complete
1aca8391092b: Pull complete
06e460b3ba1b: Pull complete
def49df025c0: Pull complete
646c72a19e83: Pull complete
db2c789841df: Pull complete
Digest: sha256:619af14d3a95c30759a1978da1b2ce375504f1af70ff9eea2a8e35febc45d747
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest
docker images
can check which mirrors we have installed, you can see that I have actually installed the mirrors of redis
% docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 40c68ed3a4d2 3 days ago 113MB
redis <none> 84c5f6e03bf0 14 months ago 104MB
mysql latest e1d7dc9731da 14 months ago 544MB
docker/getting-started latest 1f32459ef038 16 months ago 26.8MB
redis
% docker run -itd --name redis-test -p 6379:6379 redis
7267e14faf93a0e416c39eeaaf51705dc4b6dc3507a68733c20a2609ade6dcd6
docker
there are now two containers redis
and mysql
2. Initialize the database
drop database IF EXISTS test;
CREATE DATABASE test;
use test;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT "",
`age` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES (1, '李四', 11);
INSERT INTO `user` VALUES (2, '王五', 11);
3. Create the project
Next
:Web
under Spring Web
, SQL
under JDBC API
, Mybatis
, NoSQL
under Redis
, or you can leave it unselected, and you can directly pom
file in 061c1271f69d36:Next
all the way, and finally Finish
. After creating it, remember to update Maven
and install dependent packages.4. Initialization code
4.1 Global configuration file and startup class
application.yml
:server:
port: 8081
spring:
#数据库连接配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&useSSL=false
username: root
password: 123456
redis:
host: 127.0.0.1 ## redis所在的服务器IP
port: 6379
##密码,我这里没有设置,所以不填
password:
## 设置最大连接数,0为无限
pool:
max-active: 8
min-idle: 0
max-idle: 8
max-wait: -1
#mybatis的相关配置
mybatis:
#mapper配置文件
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.aphysia.spingbootdemo.model
#开启驼峰命名
configuration:
map-underscore-to-camel-case: true
logging:
level:
root: debug
SpringdemoApplication
:import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.aphysia.springdemo.mapper")
public class SpringdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringdemoApplication.class, args);
}
}
4.2 Entity class
User.java
corresponding to the user table in the database:package com.aphysia.springdemo.model;
public class User {
int id;
String name;
int age;
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;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4.3 Redis tools
Redis
Configuration class RedisConfig
:package com.aphysia.springdemo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Autowired
private RedisTemplate redisTemplate;
@Bean
public RedisTemplate redisTemplateInit() {
//设置序列化Key的实例化对象
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置序列化Value的实例化对象
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}
Redis
constant class RedisConstant
:package com.aphysia.springdemo.constant;
public class RedisConstant {
public static String ALL_USER_KEY = "allUser";
}
Redis
Tools RedisUtil
:package com.aphysia.springdemo.util;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
@Component
public class RedisUtil {
@Resource
private RedisTemplate<String, Object> redisTemplate;
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}
//============================String=============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
//================================Map=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
//============================set=============================
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
//===============================list=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
4.4 Mysql database operation
sql
file UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.aphysia.springdemo.mapper.UserMapper">
<select id="getAllUsers" resultType="com.aphysia.springdemo.model.User">
SELECT * FROM user
</select>
<update id="updateUserAge" parameterType="java.lang.Integer">
update user set age=age+1 where id =#{id}
</update>
</mapper>
mapper
interface UserMapper.java
package com.aphysia.springdemo.mapper;
import com.aphysia.springdemo.model.User;
import java.util.List;
public interface UserMapper {
List<User> getAllUsers();
int updateUserAge(Integer id);
}
4.5 Service layer
UserService
User
, which contains two methods to query all user
and update the age of user
package com.aphysia.springdemo.service;
import com.aphysia.springdemo.model.User;
import java.util.List;
public interface UserService {
public List<User> getAllUsers();
public void updateUserAge();
}
UserServiceImpl
, In order to verify that Redis is available, when we query all users, we add Redis cache, and load data from Redis first:package com.aphysia.springdemo.service.impl;
import com.aphysia.springdemo.constant.RedisConstant;
import com.aphysia.springdemo.mapper.UserMapper;
import com.aphysia.springdemo.model.User;
import com.aphysia.springdemo.service.UserService;
import com.aphysia.springdemo.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
@Service("userService")
public class UserServiceImpl implements UserService {
@Resource
UserMapper userMapper;
@Autowired
RedisUtil redisUtil;
@Override
public List<User> getAllUsers() {
List<User> users = (List<User>) redisUtil.get(RedisConstant.ALL_USER_KEY);
if(CollectionUtils.isEmpty(users)){
users = userMapper.getAllUsers();
redisUtil.set(RedisConstant.ALL_USER_KEY,users);
}
return users;
}
@Override
@Transactional
public void updateUserAge() {
redisUtil.del(RedisConstant.ALL_USER_KEY);
userMapper.updateUserAge(1);
userMapper.updateUserAge(2);
}
}
4.6 Controller control layer
TestController
:package com.aphysia.springdemo.controller;
import com.aphysia.springdemo.model.User;
import com.aphysia.springdemo.service.UserService;
import com.aphysia.springdemo.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class TestController {
@Autowired
UserService userService;
@RequestMapping("/getUserList")
@ResponseBody
public List<User> getUserList() {
return userService.getAllUsers();
}
@RequestMapping("/update")
@ResponseBody
public int update() {
userService.updateUserAge();
return 1;
}
}
4.7 pom dependency
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.aphysia</groupId>
<artifactId>springdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springdemo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
test
user
:http://localhost:8081/update
and return 1
http://localhost:8081/getUserList
again, you can see that all ages have become 12
:Redis
taken effect? It is best to be debug
, or directly look at the console, we have opened the debug
log:Redis-desktop-manager
, you can directly view it visually:demo
project is completed, and it can be initialized and used copy
Qin Huai, [161c1271f7130f Qinhuai Grocery Store ], the road to technology is not at a time, the mountains are high and the rivers are long, even if it is slow, it will never stop. Personal writing direction: Java source code analysis,
JDBC
, Mybatis
, Spring
, redis
, distributed,
refers to Offer,
LeetCode
, do not like to write articles in the series, do not like to write every article in the series , I cannot guarantee that what I have written is completely correct, but I guarantee that what I have written has been practiced or searched for information. I hope to correct any omissions or errors.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。