• 【SpringSecurity】三更草堂项目案例分析1 - 环境配置与预备


    认证


    Security 完整工作流

    在这里插入图片描述

    UsernamePasswordAuthenticationFilter:负责处理我们在登陆页面填写了用户名密码后的登陆请求。

    ExceptionTranslationFilter: 处理过滤器链中抛出的任何 AccessDeniedException 和 AuthenticationException 。

    FilterSecurityInterceptor: 负责权限校验的过滤器


    认证流程

    在这里插入图片描述

    Authentication 接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。

    AuthenticationManager 接口:定义了认证 Authentication 的方法

    UserDetailsService 接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。

    UserDetails 接口:提供核心用户信息。通过 UserDetailsService 根据用户名获取处理的用户信息要封装成 UserDetails 对象返回。然后将这些信息封装到 Authentication 对象中。


    这是完成这一模块后的文件结构,可以直接参考

    在这里插入图片描述


    需要添加的全部依赖

    除了 springboot 你可以使用 2.7.15 及以下版本之外,其他的依赖一定要按照下面的 pom 文件来写,否则部分类会因升级而无法使用!

    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-redisartifactId>
    dependency>
    
    <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>fastjsonartifactId>
        <version>1.2.33version>
    dependency>
    
    <dependency>
        <groupId>io.jsonwebtokengroupId>
        <artifactId>jjwtartifactId>
        <version>0.9.0version>
    dependency>
    
    
    <dependency>
        <groupId>com.baomidougroupId>
        <artifactId>mybatis-plus-boot-starterartifactId>
        <version>3.5.3.2version>
    dependency>
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
    dependency>
    
    <dependency>
         <groupId>org.springframework.bootgroupId>
         <artifactId>spring-boot-starter-testartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    前置准备

    redis 序列化与反序列化

    实现了 RedisSerializer 接口的 FastJsonRedisSerializer 类。
    主要功能是将对象序列化为字节数组存储到 Redis 中,或者将从 Redis 中获取的字节数组反序列化为对象

    设置了静态代码块,在类加载时执行,设置了 FastJSON 的全局配置,支持自动类型

    代码清单:/util/FastJsonRedisSerializer.java

    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import com.fasterxml.jackson.databind.JavaType;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.type.TypeFactory;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.SerializationException;
    import com.alibaba.fastjson.parser.ParserConfig;
    import org.springframework.util.Assert;
    import java.nio.charset.Charset;
    import java.nio.charset.StandardCharsets;
    
    public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
    
        // 默认字符集为UTF-8
        public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    
        // 泛型类的类型
        private Class<T> clazz;
    
        // 静态代码块,在类加载时执行,设置全局的FastJSON配置,支持自动类型
        static {
            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        }
    
        // 构造函数,传入泛型类的类型
        public FastJsonRedisSerializer(Class<T> clazz) {
            super();
            this.clazz = clazz;
        }
    
        // 序列化对象为字节数组
        @Override
        public byte[] serialize(T t) throws SerializationException {
            if (t == null) {
                return new byte[0];
            }
            // 使用FastJSON将对象转换为JSON字符串,并添加类名信息,然后将字符串转换为字节数组
            return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
        }
    
        // 反序列化字节数组为对象
        @Override
        public T deserialize(byte[] bytes) throws SerializationException {
            if (bytes == null || bytes.length <= 0) {
                return null;
            }
            // 将字节数组转换为字符串
            String str = new String(bytes, DEFAULT_CHARSET);
            // 使用FastJSON将字符串解析为对象,并指定对象的类型
            return JSON.parseObject(str, clazz);
        }
    
        // 获取JavaType对象,用于FastJSON解析时指定对象的类型
        protected JavaType getJavaType(Class<?> clazz) {
            return TypeFactory.defaultInstance().constructType(clazz);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    统一响应

    后端标配,创建一个统一响应类,返回给前端,实现标准化

    代码清单:/domain/ResponseResult.java

    import com.fasterxml.jackson.annotation.JsonInclude;
    
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class ResponseResult<T> {
        /**
         * 状态码
         */
        private Integer code;
        /**
         * 提示信息,如果有错误时,前端可以获取该字段进行提示
         */
        private String msg;
        /**
         * 查询到的结果数据,
         */
        private T data;
    
        public ResponseResult(Integer code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public ResponseResult(Integer code, T data) {
            this.code = code;
            this.data = data;
        }
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    
        public ResponseResult(Integer code, String msg, T data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    JWT

    JWT 密钥生成、解析等众多操作的工具类

    首先给出完整代码,代码清单:/util/JwtUtil.java

    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.JwtBuilder;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Base64;
    import java.util.Date;
    import java.util.UUID;
    
    /**
     * JWT工具类
     */
    public class JwtUtil {
    
        //有效期为
        public static final Long JWT_TTL = 60 * 60 * 1000L;// 60 * 60 *1000  一个小时
        //设置秘钥明文
        public static final String JWT_KEY = "sangeng";
    
        public static String getUUID() {
            String token = UUID.randomUUID().toString().replaceAll("-", "");
            return token;
        }
    
        /**
         * 生成jtw
         *
         * @param subject token中要存放的数据(json格式)
         * @return
         */
        public static String createJWT(String subject) {
            JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间
            return builder.compact();
        }
    
        /**
         * 生成jtw
         *
         * @param subject   token中要存放的数据(json格式)
         * @param ttlMillis token超时时间
         * @return
         */
        public static String createJWT(String subject, Long ttlMillis) {
            JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间
            return builder.compact();
        }
    
        private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            SecretKey secretKey = generalKey();
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            if (ttlMillis == null) {
                ttlMillis = JwtUtil.JWT_TTL;
            }
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
            return Jwts.builder()
                    .setId(uuid)              //唯一的ID
                    .setSubject(subject)   // 主题  可以是JSON数据
                    .setIssuer("sg")     // 签发者
                    .setIssuedAt(now)      // 签发时间
                    .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                    .setExpiration(expDate);
        }
    
        /**
         * 创建token
         *
         * @param id
         * @param subject
         * @param ttlMillis
         * @return
         */
        public static String createJWT(String id, String subject, Long ttlMillis) {
            JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间
            return builder.compact();
        }
    
        public static void main(String[] args) throws Exception {
            String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";
            Claims claims = parseJWT(token);
            System.out.println(claims);
        }
    
        /**
         * 生成加密后的秘钥 secretKey
         *
         * @return
         */
        public static SecretKey generalKey() {
            byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
            SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
            return key;
        }
    
        /**
         * 解析
         *
         * @param jwt
         * @return
         * @throws Exception
         */
        public static Claims parseJWT(String jwt) throws Exception {
            SecretKey secretKey = generalKey();
            return Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwt)
                    .getBody();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113

    generalKey 分析

    JwtUtil.JWT_KEY 为我们自己设置的明文公钥,是用来加密的

    Base64.getDecoder().decode 这里的解密实际上是为了把字符串公钥转化为字符数组公钥,没有所谓的解密加密的功能

    SecretKeySpec 接收字符数组的公钥以及加密算法

    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    parseJWT

    解析 JWT,很简单的三步走:
    获取秘钥、将秘钥用于解析 JWT、最后使用 getBody 获取 Claims 对象

    Claims 存储了 JWT 中的所有信息,包括签发者、签发时间与寿命等等

    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    getJwtBuilder

    生成 JWT

    setId(uuid) 使用 JAVA 自带的生成随机 UUID 的形式为每一个 JWT 设置唯一的 id,很方便

    setSubject(subject) 这个设置 JWT 主题,也就是用于表明当前 JWT 归属的方式,我们将会存储 userid

    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        // 设置签名算法为HS256
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        // 获取密钥
        SecretKey secretKey = generalKey();
    
        // 下面是计算签发时间以及JWT持续的有效时间的算法
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if (ttlMillis == null) {
            ttlMillis = JwtUtil.JWT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
    
        // 签发JWT
        return Jwts.builder()
                .setId(uuid)              //唯一的ID
                .setSubject(subject)   // 主题  可以是JSON数据
                .setIssuer("sg")     // 签发者
                .setIssuedAt(now)      // 签发时间
                .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                .setExpiration(expDate);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    createJWT

    官方给出的代码重载了三个 createJWT,这里只介绍最关键的一个

    builder.compact 用于把 JwtBuilder 对象转换成 JWT 字符串形式返回

    public static String createJWT(String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间
        return builder.compact();
    }
    
    • 1
    • 2
    • 3
    • 4

    redis 缓存类

    设置 redis 缓存操作工具方法

    代码清单:/util/RedisCache.java

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.BoundSetOperations;
    import org.springframework.data.redis.core.HashOperations;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    import org.springframework.stereotype.Component;
    
    import java.util.*;
    import java.util.concurrent.TimeUnit;
    
    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    @Component
    public class RedisCache {
        @Autowired
        public RedisTemplate redisTemplate;
    
        /**
         * 缓存基本的对象,Integer、String、实体类等
         *
         * @param key   缓存的键值
         * @param value 缓存的值
         */
        public <T> void setCacheObject(final String key, final T value) {
            redisTemplate.opsForValue().set(key, value);
        }
    
        /**
         * 缓存基本的对象,Integer、String、实体类等
         *
         * @param key      缓存的键值
         * @param value    缓存的值
         * @param timeout  时间
         * @param timeUnit 时间颗粒度
         */
        public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
            redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
        }
    
        /**
         * 设置有效时间
         *
         * @param key     Redis键
         * @param timeout 超时时间
         * @return true=设置成功;false=设置失败
         */
        public boolean expire(final String key, final long timeout) {
            return expire(key, timeout, TimeUnit.SECONDS);
        }
    
        /**
         * 设置有效时间
         *
         * @param key     Redis键
         * @param timeout 超时时间
         * @param unit    时间单位
         * @return true=设置成功;false=设置失败
         */
        public boolean expire(final String key, final long timeout, final TimeUnit unit) {
            return redisTemplate.expire(key, timeout, unit);
        }
    
        /**
         * 获得缓存的基本对象。
         *
         * @param key 缓存键值
         * @return 缓存键值对应的数据
         */
        public <T> T getCacheObject(final String key) {
            ValueOperations<String, T> operation = redisTemplate.opsForValue();
            return operation.get(key);
        }
    
        /**
         * 删除单个对象
         *
         * @param key
         */
        public boolean deleteObject(final String key) {
            return redisTemplate.delete(key);
        }
    
        /**
         * 删除集合对象
         *
         * @param collection 多个对象
         * @return
         */
        public long deleteObject(final Collection collection) {
            return redisTemplate.delete(collection);
        }
    
        /**
         * 缓存List数据
         *
         * @param key      缓存的键值
         * @param dataList 待缓存的List数据
         * @return 缓存的对象
         */
        public <T> long setCacheList(final String key, final List<T> dataList) {
            Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
            return count == null ? 0 : count;
        }
    
        /**
         * 获得缓存的list对象
         *
         * @param key 缓存的键值
         * @return 缓存键值对应的数据
         */
        public <T> List<T> getCacheList(final String key) {
            return redisTemplate.opsForList().range(key, 0, -1);
        }
    
        /**
         * 缓存Set
         *
         * @param key     缓存键值
         * @param dataSet 缓存的数据
         * @return 缓存数据的对象
         */
        public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
            BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
            Iterator<T> it = dataSet.iterator();
            while (it.hasNext()) {
                setOperation.add(it.next());
            }
            return setOperation;
        }
    
        /**
         * 获得缓存的set
         *
         * @param key
         * @return
         */
        public <T> Set<T> getCacheSet(final String key) {
            return redisTemplate.opsForSet().members(key);
        }
    
        /**
         * 缓存Map
         *
         * @param key
         * @param dataMap
         */
        public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
            if (dataMap != null) {
                redisTemplate.opsForHash().putAll(key, dataMap);
            }
        }
    
        /**
         * 获得缓存的Map
         *
         * @param key
         * @return
         */
        public <T> Map<String, T> getCacheMap(final String key) {
            return redisTemplate.opsForHash().entries(key);
        }
    
        /**
         * 往Hash中存入数据
         *
         * @param key   Redis键
         * @param hKey  Hash键
         * @param value 值
         */
        public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
            redisTemplate.opsForHash().put(key, hKey, value);
        }
    
        /**
         * 获取Hash中的数据
         *
         * @param key  Redis键
         * @param hKey Hash键
         * @return Hash中的对象
         */
        public <T> T getCacheMapValue(final String key, final String hKey) {
            HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
            return opsForHash.get(key, hKey);
        }
    
        /**
         * 删除Hash中的数据
         *
         * @param key
         * @param hkey
         */
        public void delCacheMapValue(final String key, final String hkey) {
            HashOperations hashOperations = redisTemplate.opsForHash();
            hashOperations.delete(key, hkey);
        }
    
        /**
         * 获取多个Hash中的数据
         *
         * @param key   Redis键
         * @param hKeys Hash键集合
         * @return Hash对象集合
         */
        public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
            return redisTemplate.opsForHash().multiGet(key, hKeys);
        }
    
        /**
         * 获得缓存的基本对象列表
         *
         * @param pattern 字符串前缀
         * @return 对象列表
         */
        public Collection<String> keys(final String pattern) {
            return redisTemplate.keys(pattern);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216

    web 工具类

    代码清单:/util/WebUtils.java

    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class WebUtils
    {
        /**
         * 将字符串渲染到客户端
         *
         * @param response 渲染对象
         * @param string 待渲染的字符串
         * @return null
         */
        public static String renderString(HttpServletResponse response, String string) {
            try
            {
                response.setStatus(200);
                response.setContentType("application/json");
                response.setCharacterEncoding("utf-8");
                response.getWriter().print(string);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    实体类

    后续将会查询的 User 数据表,代码下方给出建表语句

    代码清单:/domain/User.java

    import java.io.Serializable;
    import java.util.Date;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName("sys_user")
    public class User implements Serializable {
        private static final long serialVersionUID = -40356785423868312L;
    
        /**
        * 主键
        */
       @TableId
        private Long id;
        /**
        * 用户名
        */
        private String userName;
        /**
        * 昵称
        */
        private String nickName;
        /**
        * 密码
        */
        private String password;
        /**
        * 账号状态(0正常 1停用)
        */
        private String status;
        /**
        * 邮箱
        */
        private String email;
        /**
        * 手机号
        */
        private String phonenumber;
        /**
        * 用户性别(0男,1女,2未知)
        */
        private String sex;
        /**
        * 头像
        */
        private String avatar;
        /**
        * 用户类型(0管理员,1普通用户)
        */
        private String userType;
        /**
        * 创建人的用户id
        */
        private Long createBy;
        /**
        * 创建时间
        */
        private Date createTime;
        /**
        * 更新人
        */
        private Long updateBy;
        /**
        * 更新时间
        */
        private Date updateTime;
        /**
        * 删除标志(0代表未删除,1代表已删除)
        */
        private Integer delFlag;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    建表与 mysql 链接

    我把这个数据表创建在了 mysql 数据库 mp 里面

    建表语句

    CREATE TABLE `sys_user` (
      `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
      `user_name` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '用户名',
      `nick_name` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '昵称',
      `password` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '密码',
      `status` CHAR(1) DEFAULT '0' COMMENT '账号状态(0正常 1停用)',
      `email` VARCHAR(64) DEFAULT NULL COMMENT '邮箱',
      `phonenumber` VARCHAR(32) DEFAULT NULL COMMENT '手机号',
      `sex` CHAR(1) DEFAULT NULL COMMENT '用户性别(0男,1女,2未知)',
      `avatar` VARCHAR(128) DEFAULT NULL COMMENT '头像',
      `user_type` CHAR(1) NOT NULL DEFAULT '1' COMMENT '用户类型(0管理员,1普通用户)',
      `create_by` BIGINT(20) DEFAULT NULL COMMENT '创建人的用户id',
      `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
      `update_by` BIGINT(20) DEFAULT NULL COMMENT '更新人',
      `update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
      `del_flag` INT(11) DEFAULT '0' COMMENT '删除标志(0代表未删除,1代表已删除)',
      PRIMARY KEY (`id`)
    ) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户表'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    咱们进入配置文件,简要设置一下 mysql 数据库连接

    server:
      port: 10086
    
    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/mp?characterEncoding=utf-8&serverTimezone=UTC
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Driver
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    下一节完善认证部分的介绍

  • 相关阅读:
    [黑马程序员SpringBoot2]——基础篇2
    解决easyExcel模板填充时转义字符\{xxx\}失效
    编曲学习:钢琴编写 人性化、逻辑预制 工程音频导出
    JS正则表达式
    胖小酱为什么天上会打雷?
    使用c:forEach出现页面空白,没有数据
    docker构建FreeSWITCH编译环境及打包
    vuex基础教学(1)
    Java基础之抽象类和抽象方法(最简单最详细)
    3.无重复字符的最长子串
  • 原文地址:https://blog.csdn.net/delete_you/article/details/132871525