想出去旅游,想出去玩,想大吃大喝 0_o
1. 项目介绍及环境配置
2. 短信验证码登录
3. 用户信息
4. MongoDB
5. 推荐好友列表/MongoDB集群/动态发布与查看
6. 圈子动态/圈子互动
7. 即时通讯(基于第三方API)
8. 附近的人(百度地图APi)
9. 小视频
10.网关配置
11.后台管理
用户在首次登录时需要完善个人信息,包括性别、昵称、生日、城市、头像等。其中,头像数据需要做图片上传,这里采用阿里云的OSS服务作为我们的图片服务器,并且对头像要做人脸识别,非人脸照片不得上传。
实现图片上传服务,需要有存储的支持,有以下几种方案:
对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。
阿里云官网: https://www.aliyun.com/product/oss
阿里云后台: https://oss.console.aliyun.com/overview
官方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);
}
}
进入控制台可查看上传的文件:
新建 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;
}
新建 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;
}
}
编辑 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);
}
}
编辑 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
新建 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);
}
}
返回的链接可用于图片下载
人脸识别(Face Recognition)基于图像或视频中的人脸检测、分析和比对技术,提供对您已获授权前提下的私有数据的人脸检测与属性分析、人脸对比、人脸搜索、活体检测等能力。灵活应用于金融、泛安防、零售等行业场景,满足身份核验、人脸考勤、闸机通行等业务需求
官网地址: https://ai.baidu.com/tech/face
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 有图片
}
}
error_code
为 0
,表示图片中包含人脸
新建 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;
}
}
新建 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;
}
}
编辑 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();}
}
编辑 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
编辑 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 有图片
}
}
返回 true
(error_code
== 0
),则表示图片包含人脸
# 连接虚拟机
cd /root/docker-file/base/
# 启动docker镜像
docker-compose up -d
编辑 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";
}
编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/mappers/UserInfoMapper.java
文件:
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
编辑 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);
}
编辑 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);
}
}
编辑 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);
}
}
编辑 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);
}
}
编辑 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);
}
}
编辑 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;
}
}
MUMU模拟器无法实现拍照功能,所以这里使用Postman实现登录、人脸上传功能
新建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);
}
}
编辑 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);
}
}
编辑 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);
}
编辑 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);
}
}
根据API文档得知,Java实体和API相应数据 数据类型不统一,导致异常;
例如:实体类中的age
为Integer
类型,而相应数据的age
为String
新建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; //婚姻状态
}
编辑 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;
}
}
编辑 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);
}
}
编辑 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);
}
}
编辑 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);
}
}
拦截器(Interceptor)
ThreadLocal
Threadlocal使用方法:
ThreadLocal<T> threadLocal = new ThreadLocal<T>();
threadLocal.set() //将数据绑定到当前线程
threadLocal.get() //从当前线程中获取数据
新建 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;
}
}
新建 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"});
}
}
编辑 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);
}
}
编辑 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);
}
}
新建 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();
}
}
编辑 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;
}
}
编辑 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);
}
}
编辑 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);
}
}
新建 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();
}
}
启动项目运行:VMware、FinalShell(启动Doctor)、Navicat(MySQL数据库)、MUMU模拟器、IDEA(Server、Dubbo服务)
通过MUMU模拟器,启动IDEA断点调试,查看 ThreadLocal 方法是否正常启用
新建 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();
}
}
新建 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;
}
}
编辑 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());
}
}
}
编辑 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);
}
}
编辑 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;
}
}
SpringMVC提供了一套解决全局异常的处理方案,可以在代码无侵入的前提下完成异常处理。遵循逐层抛出,异常处理器统一处理的思路
编辑 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());
}
}
编辑 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);
}
}