• Dobbo微服务项目实战(详细介绍+案例源码) - 3.用户信息


    想出去旅游,想出去玩,想大吃大喝 0_o

    在这里插入图片描述

    系列文章目录

    1. 项目介绍及环境配置
    2. 短信验证码登录
    3. 用户信息
    4. MongoDB
    5. 推荐好友列表/MongoDB集群/动态发布与查看
    6. 圈子动态/圈子互动
    7. 即时通讯(基于第三方API)
    8. 附近的人(百度地图APi)
    9. 小视频
    10.网关配置
    11.后台管理



    一、业务概述

    用户在首次登录时需要完善个人信息,包括性别、昵称、生日、城市、头像等。其中,头像数据需要做图片上传,这里采用阿里云的OSS服务作为我们的图片服务器,并且对头像要做人脸识别,非人脸照片不得上传。
    在这里插入图片描述

    • 首次登录时(手机号码不存在),需要创建用户存入数据库中
    • 客户端检测首次登录需要完善用户信息
      • 填写用户基本信息
      • 上传用户头像(需要人脸认证)


    二、阿里云OSS

    1.图片上传服务

    实现图片上传服务,需要有存储的支持,有以下几种方案:

    • 直接将图片保存到服务的硬盘(springmvc将的文件上传)
      • 优点:开发便捷,成本低
      • 缺点:扩容困难
    • 使用分布式文件系统进行存储
      • 优点:容易实现扩容
      • 缺点:开发复杂度稍大(有成熟的产品可以使用,比如:FastDFS)
    • 使用第三方的存储服务
      • 优点:开发简单,拥有强大功能,免维护
      • 缺点:付费

    在这里插入图片描述


    2.概述

    对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。

    阿里云官网: https://www.aliyun.com/product/oss

    阿里云后台: https://oss.console.aliyun.com/overview

    在这里插入图片描述


    3.简易案例

    官方SDK文档: https://help.aliyun.com/document_detail/84781.html

    新建 tanhua-app-server/src/test/java/com/tanhua/test/OssTest.java 测试类:

    public class OssTest {
    
        /**
         * 将资料中的1.jpg上传到阿里云OSS
         * 存放的位置 /yyyy/MM/dd/xxxx.jpg
         */
        @Test
        public void testOss() throws FileNotFoundException {
    
            // 1. 配置图片路径
            String path = "C:\\Users\\y\\Desktop\\img\\1.jpg";
            // 2. 构造FileInputStream
            FileInputStream inputStream = new FileInputStream(new File(path));
            // 3. 拼接图片路径
            String filename = new SimpleDateFormat("yyyy/MM/dd").format(new Date()) + "/"
                    + UUID.randomUUID().toString() + "/" + path.substring(path.lastIndexOf("."));
    
    
            // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
            String endpoint = "oss-cn-beijing.aliyuncs.com";
            // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
            String accessKeyId = "LTAI4GKgob9vZ53k2SZdyAC7";
            String accessKeySecret = "LHLBvXmILRoyw0niRSBuXBZewQ30la";
            // 填写Bucket名称,例如examplebucket。
            String bucketName = "examplebucket";
            // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
            String objectName = "exampledir/exampleobject.txt";
            // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
            // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
            String filePath= "D:\\localpath\\examplefile.txt";
    
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    
            try {
                // 创建PutObjectRequest对象。
                // PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(filePath));
                PutObjectRequest putObjectRequest = new PutObjectRequest("tanhua001", filename, inputStream);
                // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
                // ObjectMetadata metadata = new ObjectMetadata();
                // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
                // metadata.setObjectAcl(CannedAccessControlList.Private);
                // putObjectRequest.setMetadata(metadata);
    
                // 上传文件。
                ossClient.putObject(putObjectRequest);
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
    
            String url = "https://tanhua001.oss-cn-beijing.aliyuncs.com/" + filename;
            System.out.println(url);
        }
    }
    
    • 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

    4.文件管理

    进入控制台可查看上传的文件:

    在这里插入图片描述



    三、封装上传文件组件

    1.创建属性配置对象

    新建 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/properties/OssProperties.java 文件:

    @Data
    @ConfigurationProperties(prefix = "tanhua.oss")
    public class OssProperties {
    
        private String accessKey;
        private String secret;
        private String bucketName;
        private String url; //域名
        private String endpoint;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.创建模板对象

    新建 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/template/OssTemplate.java 文件:

    public class OssTemplate {
    
        private OssProperties properties;
    
        public OssTemplate(OssProperties properties) {
            this.properties = properties;
        }
    
        /**
         * 文件上传
         * 参数1: 文件名称
         * 参数2: 输入流
         */
        public String upload(String path, InputStream is) {
            // 3. 拼接图片路径
            String filename = new SimpleDateFormat("yyyy/MM/dd").format(new Date()) + "/"
                    + UUID.randomUUID().toString() + "/" + path.substring(path.lastIndexOf("."));
    
    
            // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
            String endpoint = properties.getEndpoint();
            // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
            String accessKeyId = properties.getAccessKey();
            String accessKeySecret = properties.getSecret();
    
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    
            try {
                // 创建PutObjectRequest对象。
                PutObjectRequest putObjectRequest = new PutObjectRequest(properties.getBucketName(), filename, is);
                // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
                // ObjectMetadata metadata = new ObjectMetadata();
                // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
                // metadata.setObjectAcl(CannedAccessControlList.Private);
                // putObjectRequest.setMetadata(metadata);
    
                // 上传文件。
                ossClient.putObject(putObjectRequest);
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
            String url = properties.getUrl() + "/" + filename;
            return url;
        }
    }
    
    • 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

    3.自动装配

    编辑 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/TanhuaAutoConfiguration.java 文件:

    @EnableConfigurationProperties({
            SmsProperties.class,
            OssProperties.class
    })
    public class TanhuaAutoConfiguration {
    
        @Bean
        public SmsTemplate smsTemplate(SmsProperties properties) {
            return new SmsTemplate(properties);
        }
    
        @Bean
        public OssTemplate ossTemplate(OssProperties properties) {
            return new OssTemplate(properties);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4.引入OSS配置

    编辑 tanhua-app-server/src/main/resources/application.yml 文件:

    #服务端口
    server:
      port: 18080
    spring:
      application:
        name: tanhua-app-server
      redis:  #redis配置
        port: 6379
        host: 192.168.136.160
      cloud:  #nacos配置
        nacos:
          discovery:
            server-addr: 192.168.136.160:8848
    dubbo:    #dubbo配置
      registry:
        address: spring-cloud://localhost
      consumer:
        check: false
        retries: 0
    tanhua:
      sms:
        signName: 物流云商
        templateCode: SMS_106590012
        accessKey: LTAI5tNBeDJG3SiHQfnMiFuX
        secret: EbuGpw5WKoAR80p7GZj8WelLGtG4Nq
      oss:
        accessKey: LTAI5tNBeDJG3SiHQfnMiFuX
        secret: EbuGpw5WKoAR80p7GZj8WelLGtG4Nq
        endpoint: oss-cn-beijing.aliyuncs.com
        bucketName: tanhua001
        url: https://tanhua001.oss-cn-beijing.aliyuncs.com/
      aip:
        appId: 24021388
        apiKey: ZnMTwoETXnu4OPIGwGAO2H4G
        secretKey: D4jXShyinv5q26bUS78xRKgNLnB9IfZh
    
    • 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

    5.测试类

    新建 tanhua-app-server/src/test/java/com/tanhua/test/OssTest.java 文件:

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = AppServerApplication.class)
    public class OssTest {
    
        @Autowired
        private OssTemplate template;
    
        @Test
        public void testTemplateUpload() throws FileNotFoundException {
            String path = "C:\\Users\\y\\Desktop\\img\\1.jpg";
            FileInputStream inputStream = new FileInputStream(new File(path));
            String imgUrl = template.upload(path, inputStream);
            System.out.println(imgUrl);
        }
    
        /**
         * 将资料中的1.jpg上传到阿里云OSS
         * 存放的位置 /yyyy/MM/dd/xxxx.jpg
         */
        @Test
        public void testOss() throws FileNotFoundException {
    
            // 1. 配置图片路径
            String path = "C:\\Users\\y\\Desktop\\img\\1.jpg";
            // 2. 构造FileInputStream
            FileInputStream inputStream = new FileInputStream(new File(path));
            // 3. 拼接图片路径
            String filename = new SimpleDateFormat("yyyy/MM/dd").format(new Date()) + "/"
                    + UUID.randomUUID().toString() + "/" + path.substring(path.lastIndexOf("."));
    
    
            // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
            String endpoint = "oss-cn-beijing.aliyuncs.com";
            // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
            String accessKeyId = "LTAI4GKgob9vZ53k2SZdyAC7";
            String accessKeySecret = "LHLBvXmILRoyw0niRSBuXBZewQ30la";
            // 填写Bucket名称,例如examplebucket。
            String bucketName = "examplebucket";
            // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
            String objectName = "exampledir/exampleobject.txt";
            // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
            // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
            String filePath= "D:\\localpath\\examplefile.txt";
    
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    
            try {
                // 创建PutObjectRequest对象。
    //            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(filePath));
                PutObjectRequest putObjectRequest = new PutObjectRequest("tanhua001", filename, inputStream);
                // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
                // ObjectMetadata metadata = new ObjectMetadata();
                // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
                // metadata.setObjectAcl(CannedAccessControlList.Private);
                // putObjectRequest.setMetadata(metadata);
    
                // 上传文件。
                ossClient.putObject(putObjectRequest);
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
    
            String url = "https://tanhua001.oss-cn-beijing.aliyuncs.com/" + filename;
            System.out.println(url);
        }
    }
    
    • 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


    6.下载链接

    返回的链接可用于图片下载

    在这里插入图片描述


    四、百度人脸识别

    1.概述

    人脸识别(Face Recognition)基于图像或视频中的人脸检测、分析和比对技术,提供对您已获授权前提下的私有数据的人脸检测与属性分析、人脸对比、人脸搜索、活体检测等能力。灵活应用于金融、泛安防、零售等行业场景,满足身份核验、人脸考勤、闸机通行等业务需求

    官网地址: https://ai.baidu.com/tech/face

    在这里插入图片描述


    2.案例

    SDK文档: https://cloud.baidu.com/doc/FACE/s/8k37c1rqz#%E6%96%B0%E5%BB%BAaipface

    新建 tanhua-app-server/src/test/java/com/tanhua/test/FaceTest.java 文件:

    public class FaceTest {
    
        //设置APPID/AK/SK
        public static final String APP_ID = "27653276";
        public static final String API_KEY = "zbSWMK1OnrALV6ycE7647Z67";
        public static final String SECRET_KEY = "49SaFjvsS4qajv7CD45e9ExK36L83sts";
    
        public static void main(String[] args) {
            // 初始化一个AipFace
            AipFace client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
    
            // 可选:设置网络连接参数
            client.setConnectionTimeoutInMillis(2000);
            client.setSocketTimeoutInMillis(60000);
    
            // 调用接口
            String image = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202108%2F28%2F20210828122250_3b289.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002";
            String imageType = "URL";
    
            // 传入可选参数调用接口
            HashMap<String, String> options = new HashMap<String, String>();
            options.put("face_field", "age");
            options.put("max_face_num", "2");
            options.put("face_type", "LIVE");
            options.put("liveness_control", "LOW");
    
            // 人脸检测
            JSONObject res = client.detect(image, imageType, options);
            System.out.println(res.toString(2));
    
            Object error_code = res.get("error_code");
            System.out.println(error_code);
            // => 0 有图片
        }
    }
    
    • 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

    3.测试结果

    error_code0 ,表示图片中包含人脸

    在这里插入图片描述


    五.抽取模板工具_人脸识别

    1.创建属性配置对象

    新建 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/properties/AipFaceProperties.java 文件:

    @Data
    @ConfigurationProperties(prefix = "tanhua.aip")
    public class AipFaceProperties {
            private String appId;
            private String apiKey;
            private String secretKey;
    
        @Bean
        public AipFace aipFace() {
            // 初始化一个AipFace
            AipFace client = new AipFace(appId, apiKey, secretKey);
    
            // 可选:设置网络连接参数
            client.setConnectionTimeoutInMillis(2000);
            client.setSocketTimeoutInMillis(60000);
            return client;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.创建模板对象

    新建 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/template/AipFaceTemplate.java 文件:

    public class AipFaceTemplate {
    
        @Autowired
        private AipFace client;
    
        /**
         * 检测图片是否包含人脸
         * true: 包含
         * false: 不包含
         * @return
         */
        public boolean detect(String imageUrl) {
            // 调用接口
            String imageType = "URL";
    
            // 传入可选参数调用接口
            HashMap<String, String> options = new HashMap<String, String>();
            options.put("face_field", "age");
            options.put("max_face_num", "2");
            options.put("face_type", "LIVE");
            options.put("liveness_control", "LOW");
    
            // 人脸检测
            JSONObject res = client.detect(imageUrl, imageType, options);
            System.out.println(res.toString(2));
    
            Integer error_code =(Integer) res.get("error_code");
            return error_code == 0;
        }
    }
    
    • 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

    3.自动装配

    编辑 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/TanhuaAutoConfiguration.java 文件:

    @EnableConfigurationProperties({
            SmsProperties.class,
            OssProperties.class,
            AipFaceProperties.class
    })
    public class TanhuaAutoConfiguration {
    
        @Bean
        public SmsTemplate smsTemplate(SmsProperties properties) {
            return new SmsTemplate(properties);
        }
    
        @Bean
        public OssTemplate ossTemplate(OssProperties properties) {return new OssTemplate(properties);}
    
        @Bean
        public AipFaceTemplate aipFaceTemplate() {return new AipFaceTemplate();}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4.引入aip配置

    编辑 tanhua-app-server/src/main/resources/application.yml 文件:

    #服务端口
    server:
      port: 18080
    spring:
      application:
        name: tanhua-app-server
      redis:  #redis配置
        port: 6379
        host: 192.168.136.160
      cloud:  #nacos配置
        nacos:
          discovery:
            server-addr: 192.168.136.160:8848
    dubbo:    #dubbo配置
      registry:
        address: spring-cloud://localhost
      consumer:
        check: false
        retries: 0
    tanhua:
      sms:
        signName: 物流云商
        templateCode: SMS_106590012
        accessKey: LTAI5tNBeDJG3SiHQfnMiFuX
        secret: EbuGpw5WKoAR80p7GZj8WelLGtG4Nq
      oss:
        accessKey: LTAI5tNBeDJG3SiHQfnMiFuX
        secret: EbuGpw5WKoAR80p7GZj8WelLGtG4Nq
        endpoint: oss-cn-beijing.aliyuncs.com
        bucketName: tanhua001
        url: https://tanhua001.oss-cn-beijing.aliyuncs.com/
      aip:
        appId: 24021388
        apiKey: ZnMTwoETXnu4OPIGwGAO2H4G
        secretKey: D4jXShyinv5q26bUS78xRKgNLnB9IfZh
    
    • 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

    5.测试类

    编辑 tanhua-app-server/src/test/java/com/tanhua/test/FaceTest.java 文件:

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = AppServerApplication.class)
    public class FaceTest {
        @Autowired
        private AipFaceTemplate template;
    
        @Test
        public void detect() {
            boolean detect = template.detect("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202108%2F28%2F20210828122250_3b289.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002");
            System.out.println(detect);
        }
    
        //设置APPID/AK/SK
        public static final String APP_ID = "27653276";
        public static final String API_KEY = "zbSWMK1OnrALV6ycE7647Z67";
        public static final String SECRET_KEY = "49SaFjvsS4qajv7CD45e9ExK36L83sts";
    
        public static void main(String[] args) {
    
            // 初始化一个AipFace
            AipFace client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
    
            // 可选:设置网络连接参数
            client.setConnectionTimeoutInMillis(2000);
            client.setSocketTimeoutInMillis(60000);
    
            // 调用接口
            String image = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202108%2F28%2F20210828122250_3b289.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002";
            String imageType = "URL";
    
            // 传入可选参数调用接口
            HashMap<String, String> options = new HashMap<String, String>();
            options.put("face_field", "age");
            options.put("max_face_num", "2");
            options.put("face_type", "LIVE");
            options.put("liveness_control", "LOW");
    
            // 人脸检测
            JSONObject res = client.detect(image, imageType, options);
            System.out.println(res.toString(2));
    
            Object error_code = res.get("error_code");
            System.out.println(error_code);
            // => 0 有图片
        }
    }
    
    • 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

    6.测试结果

    返回 trueerror_code == 0 ),则表示图片包含人脸

    在这里插入图片描述



    六.保存用户信息

    1.接口文档

    # 连接虚拟机
    cd /root/docker-file/base/
    # 启动docker镜像
    docker-compose up -d
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述


    2.实体类

    编辑 tanhua-model/src/main/java/com/tanhua/model/domain/UserInfo.java 文件:

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserInfo implements Serializable {
    
        /**
         * 由于userinfo表和user表之间是一对一关系
         *   userInfo的id来源于user表的id
         */
        @TableId(type= IdType.INPUT)
        private Long id; //用户id
        private String nickname; //昵称
        private String avatar; //用户头像
        private String birthday; //生日
        private String gender; //性别
        private Integer age; //年龄
        private String city; //城市
        private String income; //收入
        private String education; //学历
        private String profession; //行业
        private Integer marriage; //婚姻状态
        private String tags; //用户标签:多个用逗号分隔
        private String coverPic; // 封面图片
        private Date created;
        private Date updated;
    
        //用户状态,1为正常,2为冻结
        @TableField(exist = false)
        private String userStatus = "1";
    }
    
    • 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

    3.Mapper接口

    编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/mappers/UserInfoMapper.java 文件:

    public interface UserInfoMapper extends BaseMapper<UserInfo> {
    }
    
    • 1
    • 2

    4.API接口

    编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserInfoApi.java 文件:

    public interface UserInfoApi {
        public void save(UserInfo userInfo);
    
        public void update(UserInfo userInfo);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5. 实现类Impl

    编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserInfoImpl.java 文件:

    @DubboService
    public class UserInfoImpl implements UserInfoApi{
        @Autowired
        private UserInfoMapper userInfoMapper;
    
        @Override
        public void save(UserInfo userInfo) {
            userInfoMapper.insert(userInfo);
        }
    
        @Override
        public void update(UserInfo userInfo) {
            userInfoMapper.updateById(userInfo);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    6.Controller获取请求参数

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/UserController.java 文件:

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserInfoService userInfoService;
    
        /**
         * 保存用户信息
         *      UserInfo
         *      请求头中携带的token
         */
        @PostMapping("/loginReginfo")
        public ResponseEntity loginReginfo(@RequestBody UserInfo userInfo,
                                           @RequestHeader("Authorization") String token) {
            // 1. 判断token是否合法
            boolean verifyToken = JwtUtils.verifyToken(token);
            if(!verifyToken) {
                return ResponseEntity.status(401).body(null);
            }
    
            // 2. 向userInfo中设置用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
            userInfo.setId(Long.valueOf(id));
    
            // 3. 调用service
            userInfoService.save(userInfo);
            return ResponseEntity.ok(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
    • 28
    • 29
    • 30
    • 31

    7.调用Api保存

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserInfoService.java 文件:

    @Service
    public class UserInfoService {
    
        @DubboReference
        private UserInfoApi userInfoApi;
    
        public void save(UserInfo userInfo) {
            userInfoApi.save(userInfo);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10


    七.上传用户头像

    1.接口文档

    在这里插入图片描述


    2.控制层接收图片参数

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/UserController.java 文件:

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserInfoService userInfoService;
    
        /**
         * 保存用户信息
         *      UserInfo
         *      请求头中携带的token
         */
        @PostMapping("/loginReginfo")
        public ResponseEntity loginReginfo(@RequestBody UserInfo userInfo,
                                           @RequestHeader("Authorization") String token) {
            // 1. 判断token是否合法
            boolean verifyToken = JwtUtils.verifyToken(token);
            if(!verifyToken) {
                return ResponseEntity.status(401).body(null);
            }
    
            // 2. 向userInfo中设置用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
            userInfo.setId(Long.valueOf(id));
    
            // 3. 调用service
            userInfoService.save(userInfo);
            return ResponseEntity.ok(null);
        }
    
        /**
         * 上传用户头像
         */
        @PostMapping("/loginReginfo/head")
        public ResponseEntity head(MultipartFile headPhoto, @RequestHeader("Authorization") String token) throws IOException {
    
            // 1. 判断token是否合法
            boolean verifyToken = JwtUtils.verifyToken(token);
            if(!verifyToken) {
                return ResponseEntity.status(401).body(null);
            }
    
            // 2. 向userInfo中设置用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
    
            // 3. 调用service
            userInfoService.updateHead(headPhoto, id);
            return ResponseEntity.ok(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
    • 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

    3.逻辑层进行人脸识别

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserService.java 文件:

    @Service
    public class UserService {
    
        @Autowired
        private SmsTemplate template;
    
        @Autowired
        private RedisTemplate<String, String> redisTemplate;
    
        @DubboReference
        private UserApi userApi;
    
        /**
         * 发送短信验证码
         * @param phone
         */
    
        public void sendMsg(String phone) {
            // 1. 随机生成6位数数字
            // String code = RandomStringUtils.randomNumeric(6);
            // !!! 项目开发不用真正实现短信发送
             String code = "123456";
    
            // 2. 调用template对象, 发送验证码
            // !!! 项目开发不用真正实现短信发送
            // template.sendSms(phone, code);
    
            // 3. 将验证码存入redis
            redisTemplate.opsForValue().set("CHECK_CODE_"+phone,code, Duration.ofMinutes(5));
        }
    
        /**
         * 验证登录
         * @param phone
         * @param code
         */
        public Map loginVerification(String phone, String code) {
            // 1. 从redis中获取验证码
            String redisCode = redisTemplate.opsForValue().get("CHECK_CODE_" + phone);
    
            // 2. 对验证码进行校验
            if(StringUtils.isEmpty(redisCode) || !redisCode.equals(code)) {
                throw new RuntimeException("验证码错误");
                // throw new BusinessException(ErrorResult.loginError());
            }
    
            // 3. 删除redis中的验证码
            redisTemplate.delete("CHECK_CODE_" + phone);
    
            // 4. 通过手机号查询用户
            User user = userApi.findByMobile(phone);
            boolean isNew = false;
    
            // 5. 如果用户不存在,创建用户保存到数据库
            if(user == null) {
                user = new User();
                user.setMobile(phone);
                // user.setCreated(new Date());
                // user.setUpdated(new Date());
                user.setPassword(DigestUtils.md5Hex("123456"));
                Long userId = userApi.save(user);
                user.setId(userId);
                isNew = true;
            }
    
            // 6. 通过JWT生成token(存入手机号和用户ID)
            Map tokenMap = new HashMap();
            tokenMap.put("id", user.getId());
            tokenMap.put("mobile", phone);
            String token = JwtUtils.getToken(tokenMap);
    
            // 7. 构造返回值
            Map retMap = new HashMap();
            retMap.put("token", token);
            retMap.put("isNew", isNew);
    
            return retMap;
        }
    }
    
    • 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

    4.Postman测试

    MUMU模拟器无法实现拍照功能,所以这里使用Postman实现登录、人脸上传功能

    1. 登录
      在这里插入图片描述

    2. 获取token
      在这里插入图片描述

    3. mysql数据库
      在这里插入图片描述

    4. 人脸识别

      将步骤2中获取的 token 填入Value 中:
      在这里插入图片描述
      在这里插入图片描述



    八.个人资料管理

    1.接口文档

    在这里插入图片描述


    2.获取请求参数

    新建tanhua-app-server/src/main/java/com/tanhua/server/controller/UsersController.java 文件:

    @RestController
    @RequestMapping("/users")
    public class UsersController {
    
        @Autowired
        private UserInfoService userInfoService;
    
        /**
         * 查询用户资料
         * 请求头: token
         * 请求参数: userID
         */
        @GetMapping
        public ResponseEntity users(@RequestHeader("Authorization") String token, Long userID) {
            // 1. 判断token是否合法
            boolean verifyToken = JwtUtils.verifyToken(token);
            if(!verifyToken) {
                return ResponseEntity.status(401).body(null);
            }
    
            // 2. 获取用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
    
            // 3. 判断用户ID
            if(userID == null) {
                userID = Long.valueOf(id);
            }
    
            // 4. 获取用户信息
            UserInfo userInfo = userInfoService.findById(userID);
            return ResponseEntity.ok(userInfo);
        }
    }
    
    • 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

    3.调用API查询

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserInfoService.java 文件:

    @Service
    public class UserInfoService {
    
        @DubboReference
        private UserInfoApi userInfoApi;
    
        @Autowired
        private OssTemplate ossTemplate;
    
        @Autowired
        private AipFaceTemplate aipFaceTemplate;
    
        public void save(UserInfo userInfo) {
            userInfoApi.save(userInfo);
        }
    
        /**
         * 更新用户头像
         * @param headPhoto
         * @param id
         */
        public void updateHead(MultipartFile headPhoto, Integer id) throws IOException {
            // 1. 将图片上传到阿里云OSS
            // String imageUrl = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
            // !!! 阿里云OSS收费, 这里暂时跳过
            String imageUrl = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202108%2F28%2F20210828122250_3b289.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002";
    
            // 2. 调用百度云判断图片是否包含人脸
            boolean detect = aipFaceTemplate.detect(imageUrl);
    
            // 3. 如果不包含人脸,抛出异常
            if(!detect) {
                throw new RuntimeException("图片不正确");
            // 4. 如果包含人脸,调用aip更新
            } else {
                UserInfo userInfo = new UserInfo();
                userInfo.setId(Long.valueOf(id));
                userInfo.setAvatar(imageUrl);
                userInfoApi.update(userInfo);
            }
        }
    
        /**
         * 根据id查询
         * @param id
         */
        public UserInfo findById(Long id) {
            return userInfoApi.findById(id);
        }
    }
    
    • 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

    4.API接口

    编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserInfoApi.java 文件:

    public interface UserInfoApi {
        public void save(UserInfo userInfo);
    
        public void update(UserInfo userInfo);
    
        // 根据id查询
        UserInfo findById(Long id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.Impl实现类

    编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserInfoImpl.java 文件:

    @DubboService
    public class UserInfoImpl implements UserInfoApi{
        @Autowired
        private UserInfoMapper userInfoMapper;
    
        @Override
        public void save(UserInfo userInfo) {
            userInfoMapper.insert(userInfo);
        }
    
        @Override
        public void update(UserInfo userInfo) {
            userInfoMapper.updateById(userInfo);
        }
    
        @Override
        public UserInfo findById(Long id) {
            return userInfoMapper.selectById(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    6.测试

    在这里插入图片描述

    在这里插入图片描述


    7.VO

    根据API文档得知,Java实体和API相应数据 数据类型不统一,导致异常;
    例如:实体类中的 ageInteger 类型,而相应数据的 ageString

    • VO(Value Object)值对象,通常用于服务端与界面之间的数据传递。对于一个WEB页面,用一个VO对象对应整个界面的值。
    • DTO(Data Transfer Object)数据传输对象,通常用于界面向服务端的数据传递
    • Entity最常用实体类,基本和数据表一一对应,一个实体一张表(常说的实体类,Domain)

    在这里插入图片描述


    8.VO对象

    新建tanhua-model/src/main/java/com/tanhua/model/vo/UserInfoVo.java 文件:

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserInfoVo implements Serializable {
    
        private Long id; //用户id
        private String nickname; //昵称
        private String avatar; //用户头像
        private String birthday; //生日
        private String gender; //性别
        private String age; //年龄
        private String city; //城市
        private String income; //收入
        private String education; //学历
        private String profession; //行业
        private Integer marriage; //婚姻状态
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    9.转换查询结果

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserInfoService.java 文件:

    @Service
    public class UserInfoService {
    
        @DubboReference
        private UserInfoApi userInfoApi;
    
        @Autowired
        private OssTemplate ossTemplate;
    
        @Autowired
        private AipFaceTemplate aipFaceTemplate;
    
        public void save(UserInfo userInfo) {
            userInfoApi.save(userInfo);
        }
    
        /**
         * 更新用户头像
         * @param headPhoto
         * @param id
         */
        public void updateHead(MultipartFile headPhoto, Integer id) throws IOException {
            // 1. 将图片上传到阿里云OSS
            // String imageUrl = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
            // !!! 阿里云OSS收费, 这里暂时跳过
            String imageUrl = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202108%2F28%2F20210828122250_3b289.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002";
    
            // 2. 调用百度云判断图片是否包含人脸
            boolean detect = aipFaceTemplate.detect(imageUrl);
    
            // 3. 如果不包含人脸,抛出异常
            if(!detect) {
                throw new RuntimeException("图片不正确");
            // 4. 如果包含人脸,调用aip更新
            } else {
                UserInfo userInfo = new UserInfo();
                userInfo.setId(Long.valueOf(id));
                userInfo.setAvatar(imageUrl);
                userInfoApi.update(userInfo);
            }
        }
    
        /**
         * 根据id查询
         * @param id
         */
        public UserInfoVo findById(Long id) {
            UserInfo userInfo = userInfoApi.findById(id);
            UserInfoVo vo = new UserInfoVo();
    
            // vo.setId(userInfo.getId());
            // vo.setNickname(userInfo.getNickname());
            // ...
            BeanUtils.copyProperties(userInfo, vo); // 只会copy同名同类型的属性
            if(userInfo.getAge() != null) {
                vo.setAge(userInfo.getAge().toString());
            }
    
            return vo;
        }
    }
    
    • 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

    10.数据相应

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/UsersController.java 文件:

    @RestController
    @RequestMapping("/users")
    public class UsersController {
    
        @Autowired
        private UserInfoService userInfoService;
    
        /**
         * 查询用户资料
         * 请求头: token
         * 请求参数: userID
         */
        @GetMapping
        public ResponseEntity users(@RequestHeader("Authorization") String token, Long userID) {
            // 1. 判断token是否合法
            boolean verifyToken = JwtUtils.verifyToken(token);
            if(!verifyToken) {
                return ResponseEntity.status(401).body(null);
            }
    
            // 2. 获取用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
    
            // 3. 判断用户ID
            if(userID == null) {
                userID = Long.valueOf(id);
            }
    
            // 4. 获取用户信息
            UserInfoVo userInfo = userInfoService.findById(userID);
            return ResponseEntity.ok(userInfo);
        }
    }
    
    • 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

    11.测试

    在这里插入图片描述



    九.更新个人资料

    1.接口文档

    在这里插入图片描述

    2.获取请求参数

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/UsersController.java 文件:

    @RestController
    @RequestMapping("/users")
    public class UsersController {
    
        @Autowired
        private UserInfoService userInfoService;
    
        /**
         * 查询用户资料
         * 请求头: token
         * 请求参数: userID
         */
        @GetMapping
        public ResponseEntity users(@RequestHeader("Authorization") String token, Long userID) {
            // 1. 判断token是否合法
            boolean verifyToken = JwtUtils.verifyToken(token);
            if(!verifyToken) {
                return ResponseEntity.status(401).body(null);
            }
    
            // 2. 获取用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
    
            // 3. 判断用户ID
            if(userID == null) {
                userID = Long.valueOf(id);
            }
    
            // 4. 获取用户信息
            UserInfoVo userInfo = userInfoService.findById(userID);
            return ResponseEntity.ok(userInfo);
        }
    
        /**
         * 更新用户资料
         */
        @PutMapping()
        public ResponseEntity updateUserInfo(@RequestBody UserInfo userInfo, @RequestHeader("Authorization") String token) {
            // 1. 判断token是否合法
            boolean verifyToken = JwtUtils.verifyToken(token);
            if(!verifyToken) {
                return ResponseEntity.status(401).body(null);
            }
    
            // 2. 获取用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
    
            // 3. 设置用户ID
            userInfo.setId(Long.valueOf(id));
            userInfoService.update(userInfo);
    
            return ResponseEntity.ok(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
    • 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

    3.调用dubboAPI

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserInfoService.java 文件:

    @Service
    public class UserInfoService {
    
        @DubboReference
        private UserInfoApi userInfoApi;
    
        @Autowired
        private OssTemplate ossTemplate;
    
        @Autowired
        private AipFaceTemplate aipFaceTemplate;
    
        public void save(UserInfo userInfo) {
            userInfoApi.save(userInfo);
        }
    
        /**
         * 更新用户头像
         * @param headPhoto
         * @param id
         */
        public void updateHead(MultipartFile headPhoto, Integer id) throws IOException {
            // 1. 将图片上传到阿里云OSS
            // String imageUrl = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
            // !!! 阿里云OSS收费, 这里暂时跳过
            String imageUrl = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202108%2F28%2F20210828122250_3b289.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002";
    
            // 2. 调用百度云判断图片是否包含人脸
            boolean detect = aipFaceTemplate.detect(imageUrl);
    
            // 3. 如果不包含人脸,抛出异常
            if(!detect) {
                throw new RuntimeException("图片不正确");
            // 4. 如果包含人脸,调用aip更新
            } else {
                UserInfo userInfo = new UserInfo();
                userInfo.setId(Long.valueOf(id));
                userInfo.setAvatar(imageUrl);
                userInfoApi.update(userInfo);
            }
        }
    
        /**
         * 根据id查询
         * @param id
         */
        public UserInfoVo findById(Long id) {
            UserInfo userInfo = userInfoApi.findById(id);
            UserInfoVo vo = new UserInfoVo();
    
            // vo.setId(userInfo.getId());
            // vo.setNickname(userInfo.getNickname());
            // ...
            BeanUtils.copyProperties(userInfo, vo); // 只会copy同名同类型的属性
            if(userInfo.getAge() != null) {
                vo.setAge(userInfo.getAge().toString());
            }
    
            return vo;
        }
    
        /**
         * 更新用户资料
         * @param userInfo
         */
        public void update(UserInfo userInfo) {
            userInfoApi.update(userInfo);
        }
    }
    
    • 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

    4.测试

    在这里插入图片描述



    十.拦截器

    1.解决方案

    基于ThreadLocal + 拦截器的形式统一处理
    在这里插入图片描述

    拦截器(Interceptor)

    • 是一种动态拦截方法调用的机制
    • 类似于Servlet 开发中的过滤器Filter,用于对处理器进行前置处理和后置处理
      在这里插入图片描述

    ThreadLocal

    • 线程内部的存储类,赋予了线程存储数据的能力。
    • 线程内调用的方法都可以从ThreadLocal中获取同一个对象。
    • 多个线程中ThreadLocal数据相互隔离

    Threadlocal使用方法:

    ThreadLocal<T> threadLocal = new ThreadLocal<T>();
    threadLocal.set() //将数据绑定到当前线程
    threadLocal.get() //从当前线程中获取数据
    
    • 1
    • 2
    • 3

    2.token拦截器

    新建 tanhua-app-server/src/main/java/com/tanhua/server/interceptor/TokenInterceptor.java 文件:

    public class TokenInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 1. 获取请求头
            String token = request.getHeader("Authorization");
    
            // 2. 使用工具类,判断token是否有效
            boolean verifyToken = JwtUtils.verifyToken(token);
    
            // 3. 如果token失效,返回状态码401,拦截
            if(!verifyToken) {
                response.setStatus(401);
                return false;
            }
    
            // 4. 如果token正常可用,放行
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.注册TokenInterceptor

    新建 tanhua-app-server/src/main/java/com/tanhua/server/interceptor/WebConfig.java 文件:

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new TokenInterceptor())
                    .addPathPatterns("/**")
                    // 排除不需要处理的请求链接
                    .excludePathPatterns(new String[]{"/user/login", "/user/loginVerification"});
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.接口简化(去掉token校验)

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/UsersController.java 文件:

    @RestController
    @RequestMapping("/users")
    public class UsersController {
    
        @Autowired
        private UserInfoService userInfoService;
    
        /**
         * 查询用户资料
         * 请求头: token
         * 请求参数: userID
         */
        @GetMapping
        public ResponseEntity users(@RequestHeader("Authorization") String token, Long userID) {
            // 1. 判断token是否合法
            // boolean verifyToken = JwtUtils.verifyToken(token);
            // if(!verifyToken) {
            //     return ResponseEntity.status(401).body(null);
            // }
    
            // 2. 获取用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
    
            // 3. 判断用户ID
            if(userID == null) {
                userID = Long.valueOf(id);
            }
    
            // 4. 获取用户信息
            UserInfoVo userInfo = userInfoService.findById(userID);
            return ResponseEntity.ok(userInfo);
        }
    
        /**
         * 更新用户资料
         */
        @PutMapping()
        public ResponseEntity updateUserInfo(@RequestBody UserInfo userInfo, @RequestHeader("Authorization") String token) {
            // 1. 判断token是否合法
            //  boolean verifyToken = JwtUtils.verifyToken(token);
            // if(!verifyToken) {
            //     return ResponseEntity.status(401).body(null);
            // }
    
            // 2. 获取用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
    
            // 3. 设置用户ID
            userInfo.setId(Long.valueOf(id));
            userInfoService.update(userInfo);
    
            return ResponseEntity.ok(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
    • 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

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/UserController.java 文件:

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserInfoService userInfoService;
    
        /**
         * 保存用户信息
         *      UserInfo
         *      请求头中携带的token
         */
        @PostMapping("/loginReginfo")
        public ResponseEntity loginReginfo(@RequestBody UserInfo userInfo,
                                           @RequestHeader("Authorization") String token) {
            // 1. 判断token是否合法
            // boolean verifyToken = JwtUtils.verifyToken(token);
            // if(!verifyToken) {
            //     return ResponseEntity.status(401).body(null);
            // }
    
            // 2. 向userInfo中设置用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
            userInfo.setId(Long.valueOf(id));
    
            // 3. 调用service
            userInfoService.save(userInfo);
            return ResponseEntity.ok(null);
        }
    
        /**
         * 上传用户头像
         */
        @PostMapping("/loginReginfo/head")
        public ResponseEntity head(MultipartFile headPhoto, @RequestHeader("Authorization") String token) throws IOException {
    
            // 1. 判断token是否合法
            // boolean verifyToken = JwtUtils.verifyToken(token);
            // if(!verifyToken) {
            //     return ResponseEntity.status(401).body(null);
            // }
    
            // 2. 向userInfo中设置用户ID
            Claims claims = JwtUtils.getClaims(token);
            Integer id =(Integer) claims.get("id");
    
            // 3. 调用service
            userInfoService.updateHead(headPhoto, id);
            return ResponseEntity.ok(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
    • 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

    5.测试

    在这里插入图片描述
    在这里插入图片描述

    6.Threadlocal工具类

    新建 tanhua-app-server/src/main/java/com/tanhua/server/interceptor/UserHolder.java 文件:

    /**
     * 工具类: 实现向Threadlocal储存数据的方法
     */
    public class UserHolder {
    
        private static ThreadLocal<User> tl = new ThreadLocal<>();
    
        // 将用户对象存入Threadlocal
        public static void set(User user) {
            tl.set(user);
        }
    
        // 从当前线程获取用户对象
        public static User get() {
            return tl.get();
        }
    
        // 从当前线程获取用户对象的 ID
        public static Long getUserId() {
            return tl.get().getId();
        }
    
        // 从当前线程获取用户对象的 手机号
        public static String getMobile() {
            return tl.get().getMobile();
        }
    
        // 清空
        public static void remove() {
            tl.remove();
        }
    }
    
    • 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

    7.存入ThreadLocal

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/interceptor/TokenInterceptor.java 文件:

    public class TokenInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 1. 获取请求头
            String token = request.getHeader("Authorization");
    
            // 2. 使用工具类,判断token是否有效
            boolean verifyToken = JwtUtils.verifyToken(token);
    
            // 3. 如果token失效,返回状态码401,拦截
            if(!verifyToken) {
                response.setStatus(401);
                return false;
            }
    
            // 4. 如果token正常可用,放行
    
            // 解析token,获取id和手机号,构造User对象,存入ThreadLocal
            Claims claims = JwtUtils.getClaims(token);
            Integer id = (Integer) claims.get("id");
            String mobile = (String) claims.get("mobile");
    
            User user = new User();
            user.setId(Long.valueOf(id));
            user.setMobile(mobile);
    
            UserHolder.set(user);
    
            return true;
        }
    }
    
    • 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

    8.从Threadlocal获取

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/UserController.java 文件:

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserInfoService userInfoService;
    
        /**
         * 保存用户信息
         *      UserInfo
         *      请求头中携带的token
         */
        @PostMapping("/loginReginfo")
        public ResponseEntity loginReginfo(@RequestBody UserInfo userInfo,
                                           @RequestHeader("Authorization") String token) {
            // 1. 判断token是否合法
            // boolean verifyToken = JwtUtils.verifyToken(token);
            // if(!verifyToken) {
            //     return ResponseEntity.status(401).body(null);
            // }
    
            // 2. 向userInfo中设置用户ID
            // Claims claims = JwtUtils.getClaims(token);
            // Integer id =(Integer) claims.get("id");
            // userInfo.setId(Long.valueOf(id));
             userInfo.setId(UserHolder.getUserId());
    
            // 3. 调用service
            userInfoService.save(userInfo);
            return ResponseEntity.ok(null);
        }
    
        /**
         * 上传用户头像
         */
        @PostMapping("/loginReginfo/head")
        public ResponseEntity head(MultipartFile headPhoto, @RequestHeader("Authorization") String token) throws IOException {
    
            // 1. 判断token是否合法
            // boolean verifyToken = JwtUtils.verifyToken(token);
            // if(!verifyToken) {
            //     return ResponseEntity.status(401).body(null);
            // }
    
            // 2. 向userInfo中设置用户ID
            // Claims claims = JwtUtils.getClaims(token);
            // Integer id =(Integer) claims.get("id");
    
            // 3. 调用service
            // userInfoService.updateHead(headPhoto, id);
             userInfoService.updateHead(headPhoto, UserHolder.getUserId());
            return ResponseEntity.ok(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
    • 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

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/UsersController.java 文件:

    @RestController
    @RequestMapping("/users")
    public class UsersController {
    
        @Autowired
        private UserInfoService userInfoService;
    
        /**
         * 查询用户资料
         * 请求头: token
         * 请求参数: userID
         */
        @GetMapping
        public ResponseEntity users(@RequestHeader("Authorization") String token, Long userID) {
            // 1. 判断token是否合法
            // boolean verifyToken = JwtUtils.verifyToken(token);
            // if(!verifyToken) {
            //     return ResponseEntity.status(401).body(null);
            // }
    
            // 2. 获取用户ID
            // Claims claims = JwtUtils.getClaims(token);
            // Integer id =(Integer) claims.get("id");
    
            // 3. 判断用户ID
            if(userID == null) {
                // userID = Long.valueOf(id);
                 userID = UserHolder.getUserId();
            }
    
            // 4. 获取用户信息
            UserInfoVo userInfo = userInfoService.findById(userID);
            return ResponseEntity.ok(userInfo);
        }
    
        /**
         * 更新用户资料
         */
        @PutMapping()
        public ResponseEntity updateUserInfo(@RequestBody UserInfo userInfo, @RequestHeader("Authorization") String token) {
            // 1. 判断token是否合法
            //  boolean verifyToken = JwtUtils.verifyToken(token);
            // if(!verifyToken) {
            //     return ResponseEntity.status(401).body(null);
            // }
    
            // 2. 获取用户ID
            // Claims claims = JwtUtils.getClaims(token);
            // Integer id =(Integer) claims.get("id");
    
            // 3. 设置用户ID
            // userInfo.setId(Long.valueOf(id));
            userInfo.setId(UserHolder.getUserId());
            userInfoService.update(userInfo);
    
            return ResponseEntity.ok(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
    • 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

    9.清空ThreadLocal

    新建 tanhua-app-server/src/main/java/com/tanhua/server/interceptor/TokenInterceptor.java 文件:

    public class TokenInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 1. 获取请求头
            String token = request.getHeader("Authorization");
    
            // 2. 使用工具类,判断token是否有效
            boolean verifyToken = JwtUtils.verifyToken(token);
    
            // 3. 如果token失效,返回状态码401,拦截
            if(!verifyToken) {
                response.setStatus(401);
                return false;
            }
    
            // 4. 如果token正常可用,放行
    
            // 解析token,获取id和手机号,构造User对象,存入ThreadLocal
            Claims claims = JwtUtils.getClaims(token);
            Integer id = (Integer) claims.get("id");
            String mobile = (String) claims.get("mobile");
    
            User user = new User();
            user.setId(Long.valueOf(id));
            user.setMobile(mobile);
    
            UserHolder.set(user);
    
            return true;
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            UserHolder.remove();
        }
    
    }
    
    • 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

    10.测试

    启动项目运行:VMware、FinalShell(启动Doctor)、Navicat(MySQL数据库)、MUMU模拟器、IDEA(Server、Dubbo服务)

    在这里插入图片描述


    通过MUMU模拟器,启动IDEA断点调试,查看 ThreadLocal 方法是否正常启用

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述



    十一.统一异常处理

    1.状态码

    在这里插入图片描述


    2.异常对象

    新建 tanhua-model/src/main/java/com/tanhua/model/vo/ErrorResult.java 文件:

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class ErrorResult {
    
        private String errCode = "999999";
        private String errMessage;
    
        public static ErrorResult error() {
            return ErrorResult.builder().errCode("999999").errMessage("系统异常稍后再试").build();
        }
    
        public static ErrorResult fail() {
            return ErrorResult.builder().errCode("000001").errMessage("发送验证码失败").build();
        }
    
        public static ErrorResult loginError() {
            return ErrorResult.builder().errCode("000002").errMessage("验证码失效").build();
        }
    
        public static ErrorResult faceError() {
            return ErrorResult.builder().errCode("000003").errMessage("图片非人像,请重新上传!").build();
        }
    
        public static ErrorResult mobileError() {
            return ErrorResult.builder().errCode("000004").errMessage("手机号码已注册").build();
        }
    
        public static ErrorResult contentError() {
            return ErrorResult.builder().errCode("000005").errMessage("动态内容为空").build();
        }
    
        public static ErrorResult likeError() {
            return ErrorResult.builder().errCode("000006").errMessage("用户已点赞").build();
        }
    
        public static ErrorResult disLikeError() {
            return ErrorResult.builder().errCode("000007").errMessage("用户未点赞").build();
        }
    
        public static ErrorResult loveError() {
            return ErrorResult.builder().errCode("000008").errMessage("用户已喜欢").build();
        }
    
        public static ErrorResult disloveError() {
            return ErrorResult.builder().errCode("000009").errMessage("用户未喜欢").build();
        }
    }
    
    • 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

    3.自定义异常

    新建 tanhua-app-server/src/main/java/com/tanhua/server/exception/BusinessException.java 文件:

    /**
     * 自定义异常类
     */
    @Data
    public class BusinessException extends RuntimeException{
    
        private ErrorResult errorResult;
    
        public BusinessException(ErrorResult errorResult) {
            super(errorResult.getErrMessage());
            this.errorResult = errorResult;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.抛出异常

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/LoginController.java 文件:

    @RestController
    @RequestMapping("/user")
    public class LoginController {
    
        @Autowired
        private UserService userService;
    
        /**
         * 获取登录验证码
         * 请求参数: photo (map)
         * 相应数据: void
         * 返回对象: ResponseEntity
         */
        @PostMapping("/login")
        public ResponseEntity login(@RequestBody Map map) {
            String phone = (String) map.get("phone");
            userService.sendMsg(phone);
            // return ResponseEntity.status(500).body("出错了"); // 指定状态码和返回内容
            return ResponseEntity.ok(null); // 正常返回状态码 200
        }
    
        /**
         * 校验登录
         * /user/loginVerification
         * phone
         * verificationCode
         */
        @PostMapping("/loginVerification")
        public ResponseEntity loginVerification(@RequestBody Map map) {
            try {
                // 1. 调用map集合获取请求参数
                String phone =(String) map.get("phone");
                String code =(String) map.get("verificationCode");
    
                // 2. 调用userService完成用户登录
                Map retMap = userService.loginVerification(phone, code);
    
                // 3. 构造返回
                return ResponseEntity.ok(retMap);
    
            // 抛出自定义异常
            } catch (BusinessException be) {
                ErrorResult errorResult = be.getErrorResult();
                // return ResponseEntity.status(500).body(errorResult);
                 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResult);
    
            // 抛出未知异常
            } catch (Exception e) {
               return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ErrorResult.error());
            }
        }
    }
    
    • 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

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserInfoService.java 文件:

    @Service
    public class UserInfoService {
    
        @DubboReference
        private UserInfoApi userInfoApi;
    
        @Autowired
        private OssTemplate ossTemplate;
    
        @Autowired
        private AipFaceTemplate aipFaceTemplate;
    
        public void save(UserInfo userInfo) {
            userInfoApi.save(userInfo);
        }
    
        /**
         * 更新用户头像
         * @param headPhoto
         * @param id
         */
        // public void updateHead(MultipartFile headPhoto, Integer id) throws IOException {
         public void updateHead(MultipartFile headPhoto, Long id) throws IOException {
            // 1. 将图片上传到阿里云OSS
            // String imageUrl = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
            // !!! 阿里云OSS收费, 这里暂时跳过
            String imageUrl = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202108%2F28%2F20210828122250_3b289.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002";
    
            // 2. 调用百度云判断图片是否包含人脸
            boolean detect = aipFaceTemplate.detect(imageUrl);
    
            // 3. 如果不包含人脸,抛出异常
            if(!detect) {
                // throw new RuntimeException("图片不正确");
                 throw new BusinessException(ErrorResult.faceError());
            // 4. 如果包含人脸,调用aip更新
            } else {
                UserInfo userInfo = new UserInfo();
                userInfo.setId(Long.valueOf(id));
                userInfo.setAvatar(imageUrl);
                userInfoApi.update(userInfo);
            }
        }
    
        /**
         * 根据id查询
         * @param id
         */
        public UserInfoVo findById(Long id) {
            UserInfo userInfo = userInfoApi.findById(id);
            UserInfoVo vo = new UserInfoVo();
    
            // vo.setId(userInfo.getId());
            // vo.setNickname(userInfo.getNickname());
            // ...
            BeanUtils.copyProperties(userInfo, vo); // 只会copy同名同类型的属性
            if(userInfo.getAge() != null) {
                vo.setAge(userInfo.getAge().toString());
            }
    
            return vo;
        }
    
        /**
         * 更新用户资料
         * @param userInfo
         */
        public void update(UserInfo userInfo) {
            userInfoApi.update(userInfo);
        }
    }
    
    • 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

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserService.java 文件:

    @Service
    public class UserService {
    
        @Autowired
        private SmsTemplate template;
    
        @Autowired
        private RedisTemplate<String, String> redisTemplate;
    
        @DubboReference
        private UserApi userApi;
    
        /**
         * 发送短信验证码
         * @param phone
         */
    
        public void sendMsg(String phone) {
            // 1. 随机生成6位数数字
            // String code = RandomStringUtils.randomNumeric(6);
            // !!! 项目开发不用真正实现短信发送
             String code = "123456";
    
            // 2. 调用template对象, 发送验证码
            // !!! 项目开发不用真正实现短信发送
            // template.sendSms(phone, code);
    
            // 3. 将验证码存入redis
            redisTemplate.opsForValue().set("CHECK_CODE_"+phone,code, Duration.ofMinutes(5));
        }
    
        /**
         * 验证登录
         * @param phone
         * @param code
         */
        public Map loginVerification(String phone, String code) {
            // 1. 从redis中获取验证码
            String redisCode = redisTemplate.opsForValue().get("CHECK_CODE_" + phone);
    
            // 2. 对验证码进行校验
            if(StringUtils.isEmpty(redisCode) || !redisCode.equals(code)) {
                // throw new RuntimeException("验证码错误");
                throw new BusinessException(ErrorResult.loginError());
            }
    
            // 3. 删除redis中的验证码
            redisTemplate.delete("CHECK_CODE_" + phone);
    
            // 4. 通过手机号查询用户
            User user = userApi.findByMobile(phone);
            boolean isNew = false;
    
            // 5. 如果用户不存在,创建用户保存到数据库
            if(user == null) {
                user = new User();
                user.setMobile(phone);
                // user.setCreated(new Date());
                // user.setUpdated(new Date());
                user.setPassword(DigestUtils.md5Hex("123456"));
                Long userId = userApi.save(user);
                user.setId(userId);
                isNew = true;
            }
    
            // 6. 通过JWT生成token(存入手机号和用户ID)
            Map tokenMap = new HashMap();
            tokenMap.put("id", user.getId());
            tokenMap.put("mobile", phone);
            String token = JwtUtils.getToken(tokenMap);
    
            // 7. 构造返回值
            Map retMap = new HashMap();
            retMap.put("token", token);
            retMap.put("isNew", isNew);
    
            return retMap;
        }
    }
    
    • 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

    5.测试

    在这里插入图片描述


    6.解决方案

    SpringMVC提供了一套解决全局异常的处理方案,可以在代码无侵入的前提下完成异常处理。遵循逐层抛出,异常处理器统一处理的思路

    在这里插入图片描述

    • 项目中可能存在不可预知的各种异常,如:空指针,数组越界等。针对这类异常,可以直接在异常处理器中统一处理
    • 还有一类是可预知的错误,如图片不合法,验证码错误等等。这类错误也可以理解为业务异常,可以通过自定义异常类来处理;

    7.自定义统一异常处理

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/exception/ExceptionAdvice.java 文件:

    /**
     * 自定义统一异常处理
     */
    // 1. 通过注解,声明异常处理类
    @ControllerAdvice
    public class ExceptionAdvice {
    
        // 2. 方法上编写注解,指定此方法可以处理的异常类型
        @ExceptionHandler(BusinessException.class)
    
        // 3. 编写方法,在方法内部处理异常,构造响应数据
        public ResponseEntity handlerException(BusinessException be) {
            // 打印报错信息
            be.printStackTrace();
            ErrorResult errorResult = be.getErrorResult();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResult);
        }
    
        // 4. 处理未知错误
        @ExceptionHandler(Exception.class)
        public ResponseEntity handlerException1(Exception be) {
            be.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ErrorResult.error());
        }
    }
    
    • 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

    8.简化异常处理(try_catch)

    编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/LoginController.java 文件:

    @RestController
    @RequestMapping("/user")
    public class LoginController {
    
        @Autowired
        private UserService userService;
    
        /**
         * 获取登录验证码
         * 请求参数: photo (map)
         * 相应数据: void
         * 返回对象: ResponseEntity
         */
        @PostMapping("/login")
        public ResponseEntity login(@RequestBody Map map) {
            String phone = (String) map.get("phone");
            userService.sendMsg(phone);
            // return ResponseEntity.status(500).body("出错了"); // 指定状态码和返回内容
            return ResponseEntity.ok(null); // 正常返回状态码 200
        }
    
        /**
         * 校验登录
         * /user/loginVerification
         * phone
         * verificationCode
         */
        @PostMapping("/loginVerification")
        public ResponseEntity loginVerification(@RequestBody Map map) {
            int i = 1/0; // 测试抛出异常(记得注释掉)
    
            // 1. 调用map集合获取请求参数
            String phone = (String) map.get("phone");
            String code = (String) map.get("verificationCode");
    
            // 2. 调用userService完成用户登录
            Map retMap = userService.loginVerification(phone, code);
    
            // 3. 构造返回
            return ResponseEntity.ok(retMap);
        }
    }
    
    • 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

    9.测试

    在这里插入图片描述

  • 相关阅读:
    Linux上防火墙操作
    DataX二次开发——(9)新增s3reader和s3writer模块
    yolov8 snpe Dynamic value for tensor name: 769, is not supported.
    制作含有音频、视频的网页
    分布式通过tcp控制开关
    web课程设计使用html+css+javascript+jquery技术制作个人介绍6页
    163_技巧_Power BI 一键批量建立自定义字段参数
    注册中心Eureka与Nacos
    excel单元格合并策略
    集中采购如何节省企业时间和金钱?
  • 原文地址:https://blog.csdn.net/weixin_45137565/article/details/127059544