飞盘是给狗玩的吧
1. 项目介绍及环境配置
2.短信验证码登录
3. 用户信息
4. MongoDB
5. 推荐好友列表/MongoDB集群/动态发布与查看
6. 圈子动态/圈子互动
7. 即时通讯(基于第三方API)
8. 附近的人(百度地图APi)
9. 小视频
10.网关配置
11.后台管理
官方网站: https://www.aliyun.com/product/sms
官方文档: https://help.aliyun.com/document_detail/101414.html
API示例: https://next.api.aliyun.com/api/Dysmsapi/2017-05-25/SendSms
新建 tanhua-app-server/src/test/java/com/tanhua/test/Sample.java
实现类:
public class Sample {
public static void main(String[] args_) throws Exception {
// 手动输入 accessKeyId (之后动态配置)
String accessKeyId = "****";
String accessKeySecret= "****";
// 配置对象阿里云
Config config = new Config()
// 您的AccessKey ID
.setAccessKeyId(accessKeyId)
// 您的AccessKey Secret
.setAccessKeySecret(accessKeySecret);
// 访问的域名
config.endpoint = "dysmsapi.aliyuncs.com";
// 创建请求客户端对象
com.aliyun.dysmsapi20170525.Client client = new com.aliyun.dysmsapi20170525.Client(config);
// 设置短信参数
SendSmsRequest sendSmsRequest = new SendSmsRequest()
.setPhoneNumbers("18618412321") //目标手机号
.setSignName("物流云商") //签名名称
.setTemplateCode("SMS_205134115") //短信模板code
.setTemplateParam("{\"code\":\"1234\"}"); //模板中变量替换
// 复制代码运行请自行打印 API 的返回值
SendSmsResponse response = client.sendSms(sendSmsRequest);
// response.body.message code = OK 代表成功
SendSmsResponseBody body = response.getBody();
}
}
调试 Sample.main()
方法查看返回结果
企业开发中,往往将常见工具类封装抽取,以简洁便利的方式供其他工程模块使用。而
SpringBoot
的自动装配机制可以方便的实现组件抽取。
新建 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/template/SmsTemplate.java
文件:
public class SmsTemplate {
public void sendSms(String mobile, String code) {
// 填写阿里云 accessKeyId
String accessKeyId = "****";
String accessKeySecret= "****";
try {
Config config = new Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret);
config.endpoint = "dysmsapi.aliyuncs.com";
com.aliyun.dysmsapi20170525.Client client = new com.aliyun.dysmsapi20170525.Client(config);
SendSmsRequest sendSmsRequest = new SendSmsRequest()
.setPhoneNumbers(mobile)
.setSignName("物流云商")
.setTemplateCode("SMS_205134115")
.setTemplateParam("{\"code\":\""+ code +"\"}");
SendSmsResponse response = client.sendSms(sendSmsRequest);
// response.body.message code = OK 代表成功
SendSmsResponseBody body = response.getBody();
// 打印返回结果
System.out.println(body.getMessage());
} catch(Exception e) {
e.printStackTrace();
}
}
}
新建 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/TanhuaAutoConfiguration.java
文件:
public class TanhuaAutoConfiguration {
@Bean
public SmsTemplate smsTemplate() {
return new SmsTemplate();
}
}
新建 tanhua-autoconfig/src/main/resources/META-INF/spring.factories
文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tanhua.autoconfig.TanhuaAutoConfiguration
新建 tanhua-app-server/src/main/resources/application.yml
文件:
spring:
application:
name: tanhua-app-server
新建 tanhua-app-server/src/main/java/com/tanhua/server/AppServerApplication.java
启动类:
//启动类
@SpringBootApplication
public class AppServerApplication {
public static void main(String[] args) {
SpringApplication.run(AppServerApplication.class,args);
}
}
新建 tanhua-app-server/src/test/java/com/tanhua/test/SmsTemplateTest.java
测试类:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class SmsTemplateTest {
// 注入
@Autowired
private SmsTemplate smsTemplate;
// 测试
@Test
public void testSendSms() {
smsTemplate.sendSms("15112341234", "5678");
}
}
调试 SmsTemplateTest.main()
方法查看返回结果
编辑 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
tanhua:
sms:
signName: 物流云商
templateCode: SMS_106590012
accessKey: ****
secret: ****
新建 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;
public void sendMsg(String phone) {
// 1. 随机生成6位数数字
String code = RandomStringUtils.randomNumeric(6);
// 2. 调用template对象, 发送验证码
template.sendSms(phone, code);
// 3. 将验证码存入redis
redisTemplate.opsForValue().set("CHECK_CODE_" + phone, code, Duration.ofMinutes(5));
}
}
新建 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(Map map) {
String phone = (String) map.get("phone");
userService.sendMsg(phone);
// return ResponseEntity.status(500).body("出错了"); // 指定状态码和返回内容
return ResponseEntity.ok(null); // 正常返回状态码 200
}
}
YAPI接口地址: http://192.168.136.160:3000/project/19/interface/api/94
# 如果API文档打不开,是因为项目YAPI未启动
# 连接虚拟机
cd /root/docker-file/base/
# 启动docker镜像
docker-compose up -d
编辑tanhua-app-server/src/main/java/com/tanhua/server/controller/LoginController.java
文件:
...
return ResponseEntity.status(500).body("出错了"); // 指定状态码和返回内容
// return ResponseEntity.ok(null); // 正常返回状态码 200
JSON Web token 简称 JWT , 是用于对应用程序上的用户进行身份验证的标记。也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他 session 数据。此特性便于可伸缩性, 同时保证应用程序的安全
官方网址: https://jwt.io/
新增 tanhua-app-server/src/test/java/com/tanhua/test/JwtTest.java
文件:
public class JwtTest {
// 生成token
@Test
public void testJwtCreateToken() {
// 1. 准备数据
Map map = new HashMap();
map.put("id", 1);
map.put("mobile", "13800138000");
// 2. 使用JWT工具类生成token
long now = System.currentTimeMillis();
String token = Jwts.builder()
.signWith(SignatureAlgorithm.HS512, "itcast") // 指定加密算法
.setClaims(map) // 写入数据
.setExpiration(new Date(now + 30000))
.compact();
System.out.println(token);
// => eyJhbGciOiJIUzUxMiJ9.eyJtb2JpbGUiOiIxMzgwMDEzODAwMCIsImlkIjoxLCJleHAiOjE2NjM5MzA5NDd9.blu3bhMCaEDkaKbolQNFNBrLT5-_2yhHInPKnXbdtm38dW6Cvh6swmtjdVuLxro_OIaduZw9_hLLA9BbMKtCxg
}
// 解析token
/**
* ExpiredJwtException: token过期
* SignatureException: token不合法
*/
@Test
public void testParseToken() {
String token = "eyJhbGciOiJIUzUxMiJ9.eyJtb2JpbGUiOiIxMzgwMDEzODAwMCIsImlkIjoxLCJleHAiOjE2NjM5MzA5NDd9.blu3bhMCaEDkaKbolQNFNBrLT5-_2yhHInPKnXbdtm38dW6Cvh6swmtjdVuLxro_OIaduZw9_hLLA9BbMKtCxg";
try {
Claims claims = Jwts.parser()
.setSigningKey("itcast")
.parseClaimsJws(token)
.getBody();
Object id = claims.get("id");
Object mobile = claims.get("mobile");
System.out.println(id + "--" + mobile);
// => 1--13800138000
} catch (ExpiredJwtException e) {
System.out.println("token已过期");
} catch (SignatureException e) {
System.out.println("token不合法");
}
}
}
新建 tanhua-model/src/main/java/com/tanhua/model/domain/User.java
文件:
@Data
@AllArgsConstructor //满参构造方法
@NoArgsConstructor //无参构造方法
public class User implements Serializable {
private Long id;
private String mobile;
private String password;
private Date created;
private Date updated;
}
新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/mappers/UserMapper.java
文件:
public interface UserMapper extends BaseMapper<User> {
}
新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java
文件:
@DubboService
public class UserApiImpl implements UserApi {
@Autowired
private UserMapper userMapper;
// 根据手机号查询用户
public User findByMobile(String mobile) {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("mobile", mobile);
return userMapper.selectOne(qw);
}
}
新建 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java
文件:
public interface UserApi {
// 根据手机号查询用户
User findByMobile(String mobile);
}
新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/DubboDBApplication.java
文件:
@SpringBootApplication
@MapperScan("com.tanhua.dubbo.mappers")
public class DubboDBApplication {
public static void main(String[] args) {
SpringApplication.run(DubboDBApplication.class, args);
}
}
新建 tanhua-dubbo/tanhua-dubbo-db/src/main/resources/application.yml
文件:
server:
port: 18081
spring:
application:
name: tanhua-dubbo-db
datasource:
driver-class-name: com.mysql.jdbc.Driver
# 也可以用虚拟机的数据库 localhost:3306 -> 127.0.0.1:3306
url: jdbc:mysql://localhost:3306/tanhua?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
username: root # 本地数据库的用户名
password: 123456 # 本地数据库的密码
cloud:
nacos:
discovery:
server-addr: 192.168.136.160:8848
dubbo:
protocol:
name: dubbo
port: 20881
registry:
address: spring-cloud://localhost
scan:
base-packages: com.tanhua.dubbo.api #dubbo中包扫描
mybatis-plus:
global-config:
db-config:
table-prefix: tb_ # 表名前缀
id-type: auto # id策略为自增长
Nacos地址: http://192.168.136.160:8848/nacos
新建 tanhua-app-server/src/test/java/com/tanhua/test/UserApiTest.java
文件:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class UserApiTest {
@DubboReference
private UserApi userApi;
@Test
public void testFindByMobile() {
User user = userApi.findByMobile("13800138000");
System.out.println(user);
}
}
执行 UserApiTest.main()
方法查看返回结果(User(id: 100, mobile: 13800138000, pass…))
新建 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) {
// 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);
}
}
新建 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("验证码错误");
}
// 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;
}
}
新建 tanhua-commons/src/main/java/com/tanhua/commons/JwtUtils.java
文件:
public class JwtUtils {
// TOKEN的有效期1小时(S)
private static final int TOKEN_TIME_OUT = 1 * 3600;
// 加密KEY
private static final String TOKEN_SECRET = "itcast";
// 生成Token
public static String getToken(Map params) {
long currentTime = System.currentTimeMillis();
return Jwts.builder()
.signWith(SignatureAlgorithm.HS512, TOKEN_SECRET) //加密方式
.setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000)) //过期时间戳
.addClaims(params)
.compact();
}
/**
* 获取Token中的claims信息
*/
public static Claims getClaims(String token) {
return Jwts.parser()
.setSigningKey(TOKEN_SECRET)
.parseClaimsJws(token).getBody();
}
/**
* 是否有效 true-有效,false-失效
*/
public static boolean verifyToken(String token) {
if (StringUtils.isEmpty(token)) {
return false;
}
try {
Claims claims = Jwts.parser()
.setSigningKey("itcast")
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
return false;
}
return true;
}
}
新建 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java
文件:
public interface UserApi {
// 根据手机号查询用户
User findByMobile(String phone);
// 保存用户, 返回用户ID
Long save(User user);
}
新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java
文件:
@DubboService
public class UserApiImpl implements UserApi {
@Autowired
private UserMapper userMapper;
// 根据手机号查询用户
public User findByMobile(String mobile) {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("mobile", mobile);
return userMapper.selectOne(qw);
}
// 保存用户,返回用户ID
@Override
public Long save(User user) {
userMapper.insert(user);
return user.getId();
}
}
mysql数据库:
新建 tanhua-model/src/main/java/com/tanhua/model/domain/BasePojo.java
文件:
@Data
public abstract class BasePojo implements Serializable {
@TableField(fill = FieldFill.INSERT) //自动填充
private Date created;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updated;
}
编辑 tanhua-model/src/main/java/com/tanhua/model/domain/User.java
文件:
@Data
@AllArgsConstructor //满参构造方法
@NoArgsConstructor //无参构造方法
public class User extends BasePojo {
private Long id;
private String mobile;
private String password;
}
新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/handler/MyMetaObjectHandler.java
文件:
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
Object created = getFieldValByName("created", metaObject);
if (null == created) {
//字段为空,可以进行填充
setFieldValByName("created", new Date(), metaObject);
}
Object updated = getFieldValByName("updated", metaObject);
if (null == updated) {
//字段为空,可以进行填充
setFieldValByName("updated", new Date(), metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
//更新数据时,直接更新字段
setFieldValByName("updated", new Date(), metaObject);
}
}
1. IP地址
设置 -> WIFI -> 高级 -> IP地址
2. 修改服务器配置
启动 探花 APP
3. 新用户 登录、注册
4. 首页(登录成功)