前期准备
创建一个微服务模块,导入pom依赖,添加配置文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.pure</groupId>
<artifactId>pure_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7878/eureka/
instance:
prefer-ip-address: true #是为了在线上时模块之间能够跨域访问
jwt:
config:
key: #这是盐
好友微服务的实现前提是要登陆验证
添加拦截器【自己写】
JwtInterceptor示例代码:
//Jwt拦截器,将公共代码写在这里
//SpringMVC配置有哪有些
//主键扫描创建实体类
//开启MVC注解支持
//配置视图解析器
//释放静态资源
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
private JwtUtil jwtUtil;
public boolean preHandle ( HttpServletRequest request,HttpServletResponse response,Object handler )
throws Exception {
System.out.println ( "经过了拦截器" );
//无论如何都放行,具体能不能操作还是在具体的操作中去判断
//拦截器只负责把有请求头的token进行解析验证
String header = request.getHeader ( "Authorization" );
if (header != null && !"".equals ( header )) {
//如果包含有头信息Authorization,就对其进行解析
if (header.startsWith ( "Bearer " )) {//是以Bearer开头得到token
String token = header.substring ( 7 );
try {
Claims claims = jwtUtil.parseJWT ( token );
String roles = (String) claims.get ( "roles" );
//这是管理员的权限判断
if (roles != null && roles.equals ( "admin" )) {
request.setAttribute ( "claims_admin",claims );
}
//普通用户的判断
if (roles != null && roles.equals ( "user" )) {
request.setAttribute ( "claims_user",claims );
}
} catch (Exception e) {
throw new RuntimeException ( );
}
}
}
return true;
}
InterceptorConfig示例代码
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Autowired
private JwtInterceptor jwtInterceptor;
//注册拦截器,要声名拦截器对象和拦截的请求
protected void addInterceptors ( InterceptorRegistry registry ) {
registry.addInterceptor ( jwtInterceptor )
.addPathPatterns ( "/**" )
.excludePathPatterns ( "/**/login/**" );
}
}
启动类配置:
需要用Feign去调用其他模块的服务,在启动类上添加相关注解,需要获取当前用户的userId,也需要将JwtUtils注入到Bean
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableEurekaClient
public class FriendApplication {
public static void main ( String[] args ) {
SpringApplication.run ( FriendApplication.class,args );
}
@Bean
public JwtUtil jwtUtil () {
return new JwtUtil ( );
}
}
好友微服务业务分析
首先设想几种情况
1、当前用户A喜欢用户B,B不喜欢A
2、当前用户A不喜欢用户B,B喜欢A
2、用户A和用户B相互喜欢
4、用户A不喜欢用户B,B也不喜欢A
5、喜欢之后,A和B粉丝数,关注数也要随着更新
还有另外两种种情况
1、A把B拉入黑名单,或者B把A拉入黑名单
2、删除好友,单向双向删除
全部的情况也就这几种
那我们就得去创建数据库了
好友,一个非好友
好友表字段分别为,userId、friendId、isLike【喜欢为1,不喜欢为0】
非好友表字段就存userId、friendId
A把B拉入黑名单,或者B把A拉入黑名单也有单向,和双向拉黑
那么我们需要联合主键去在数据库中判断
userId和friendId,好友表和非好友表
#############################
具体怎么判断,我的想法是这样的
1、如果A喜欢B,A的isLike加一 【在代码里,要注意userId和friendId的前后顺序,她们是联合主键】
2、A喜欢B,B不喜欢A,B的isLike为0,A的isLike为1【注意,是联合主键】
3、两个都互相不喜欢,各自的isLike都为0
注:这里的操作要在用户表中更新粉丝数和关注数,加一操作
那么删除好友和拉黑怎么做呢
A拉黑B,以A为主键在非好友表中保存A的userId和B的userId
反之B也一样
但是,删除之后,各自的用户表中,粉丝数和关注数要执行减一操作【在公司的实际开发中可不是真删除】
代码实现
我们需要通过 Feign去调用User模块服务
1、在需要调用其他服务的启动类上加上@EnableFeignClients注解
2、在服务调用接口添加@FeignClient ( “你要调用的服务名称” )
3、前提是Eureka服务器已经搭建以及相互调用的模块加了@EnableEurekaClient注解,将服务注册进Eureka
可以参考我这篇文章
更新粉丝数和关注数是在UserService中的操作
具体实现
Friend模块加上
UserClient
@FeignClient ( "pure-user" )
public interface UserClient {
@RequestMapping ( value = "/user/{userid}/{friendid}/{type}", method = RequestMethod.PUT )
//字段要保持一直,不然它找不着
public void UpdateFansCountAndFollowCount ( @PathVariable ( "userid" ) String userid,@PathVariable ( "friendid" ) String friendid,@PathVariable ( "type" ) int type );
}
User模块
UserService
/**
* 更新好友的粉丝数和用户的关注数
* 这是服务之间的调用,不用Result
*/
@Transactional
public void UpdateFansCountAndFollowCount ( int type,String userid,String friendid ) {
userDao.UpdateFansCount(type,friendid); //粉丝数
userDao.UpdateFollowCount(type,userid);
}
UserDao
public interface UserDao extends JpaRepository<User,String>,JpaSpecificationExecutor<User>{
@Modifying
@Query(value = "UPDATE tb_user SET fanscount = fanscount+? WHERE id = ?",nativeQuery = true)
public void UpdateFansCount ( int type,String friendid );
@Modifying
@Query(value = "UPDATE tb_user SET followcount = followcount+? WHERE id = ?",nativeQuery = true)
public void UpdateFollowCount ( int type,String userid );
}
Friend模块
FriendController
@RestController
@RequestMapping ( "/friend" )
public class FriendController {
@Autowired
private HttpServletRequest request;
@Autowired
private FriendService friendService;
@Autowired
private UserClient userClient;
/**
* * /friend/like/{friendid}/{type}
* * 添加好友或非好友
*
* @return
*/
@RequestMapping ( value = "/like/{friendid}/{type}", method = RequestMethod.PUT )
public Result AddFriend ( @PathVariable String friendid,@PathVariable String type ) {
//验证是否登陆,并且拿到当前用户id
Claims claims = (Claims) request.getAttribute ( "claims_user" ); //这里强转类型
if (claims == null) {
//进入这一步,说明当前角色不是普通用户,或者未登录
return new Result ( false,StatusCode.ACCESS_ERROR );
}
//得到当前用户id
String userId = claims.getId ( );
//判断是添加好友还是非好友
if (type != null) {
if (type.equals ( "1" )) {
//添加好友
int flag = friendService.AddFidend ( userId,friendid );
if (flag == 0) {
return new Result ( false,StatusCode.ADD_FRIEND_ERROR );
}
if (flag == 1) {
userClient.UpdateFansCountAndFollowCount ( userId,friendid,1 );
return new Result ( true,StatusCode.ADD_FRIEND_SUCCESS );
}
} else if (type.equals ( "2" )) {
//添加非好友
int flag = friendService.AddNoFriend ( userId,friendid );
if (flag == 0) {
return new Result ( false,StatusCode.ADD_NOFRIEND_ERROR );
}
if (flag == 1) {
return new Result ( true,StatusCode.ADD_NOFRIEND_SUCCESS );
}
}
return new Result ( false,StatusCode.PARAMETER_ERROR );
} else {
return new Result ( false,StatusCode.PARAMETER_ERROR );
}
}
/**
* /{friendid}
* 删除好友
*/
@RequestMapping ( value = "/{friendid}", method = RequestMethod.DELETE )
public Result DeleteFriend ( @PathVariable String friendid ) {
//验证是否登陆,并且拿到当前用户id
Claims claims = (Claims) request.getAttribute ( "claims_user" ); //这里强转类型
if (claims == null) {
//进入这一步,说明当前角色不是普通用户,或者未登录
return new Result ( false,StatusCode.ACCESS_ERROR );
}
//得到当前用户id
String userId = claims.getId ( );
friendService.DeleteFriend ( userId,friendid );
userClient.UpdateFansCountAndFollowCount ( userId,friendid,-1 );
return new Result ( true,StatusCode.DELETE_OK );
}
}
代码中有注释,就不解释了
FriendService
@Service
@Transactional
public class FriendService {
@Autowired
private FriendMapper friendMapper;
@Autowired
private NoFriendMapper noFriendMapper;
public int AddFidend ( String userId,String friendid ) {
//先判断useId到friendId是否有数据,有就是重复添加数据,返回0
Friend friend = friendMapper.findByUseridAndFriendid ( userId,friendid );
if (friend != null) {
return 0;
}
//直接添加好友,让好友表中userId到friendId的type为0
friend = new Friend ( );
friend.setUserid ( userId );
friend.setFriendid ( friendid );
friend.setIslike ( "0" );
friendMapper.save ( friend );
//判断userId到friedId是否有数据,有就是把双方的数据改为1
if (friendMapper.findByUseridAndFriendid ( friendid,userId ) != null) {
//把双方的isLike都改为1
friendMapper.upDateIsLike ( "1",userId,friendid );
friendMapper.upDateIsLike ( "1",friendid,userId );
}
return 1;
}
public int AddNoFriend ( String userId,String friendid ) {
//先判断是否已经是非好友
NoFriend noFriend = noFriendMapper.findByUseridAndFriendid ( userId,friendid );
if (noFriend != null) {
return 0;
}
noFriend = new NoFriend ( );
noFriend.setUserid ( userId );
noFriend.setFriendid ( friendid );
noFriendMapper.save ( noFriend );
return 1;
}
/**
* /{friendid}
* 删除好友
*/
public void DeleteFriend ( String userId,String friendid ) {
//先删除好友表中userid到friendid的数据
friendMapper.DeleteFriend ( userId,friendid );
//更新friendid到userId的islike为0
friendMapper.upDateIsLike ( "0",friendid,userId );
//非好友表中添加数据
NoFriend noFriend = new NoFriend ( );
noFriend.setUserid ( userId );
noFriend.setFriendid ( friendid );
noFriendMapper.save ( noFriend );
}
}
这只是本人的开发经验分享,还有很多不成熟的地方,请指导!!!!