API网关有很多实现方式,我们通过SpringCloud Gateway实现
使用Nacos作为配置中心
org.springframework.cloud spring-cloud-starter-gateway com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.boot spring-boot-starter-actuator com.itheima tanhua-commons 1.0-SNAPSHOT
@SpringBootApplication
public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);}
}
package com.itheima.gateway.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;/*** 跨域支持*/
@Configuration
public class CorsConfig {@Beanpublic CorsWebFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();config.addAllowedMethod("*");config.addAllowedOrigin("*");config.addAllowedHeader("*");UrlBasedCorsConfigurationSource source =new UrlBasedCorsConfigurationSource(new PathPatternParser());source.registerCorsConfiguration("/**", config);return new CorsWebFilter(source);}
}
server:port: 8888
spring:profiles:active: prodapplication:name: tanhua-gatewaycloud:nacos:discovery:server-addr: 192.168.136.160:8848gateway:globalcors:add-to-simple-url-handler-mapping: truecorsConfigurations:'[/**]':allowedHeaders: "*"allowedOrigins: "*"allowedMethods:- GET- POST- DELETE- PUT- OPTION
server:port: 8888
spring:profiles:active: prodapplication:name: tanhua-gatewaycloud:nacos:discovery:server-addr: 192.168.136.160:8848gateway:globalcors:add-to-simple-url-handler-mapping: truecorsConfigurations:'[/**]':allowedHeaders: "*"allowedOrigins: "*"allowedMethods:- GET- POST- DELETE- PUT- OPTIONroutes:# 探花系统- id: tanhua-app-serveruri: lb://tanhua-app-serverpredicates:- Path=/app/**filters:- StripPrefix= 1# 后台系统- id: tanhua-adminuri: lb://tanhua-adminpredicates:- Path=/admin/**filters:- StripPrefix= 1
gateway:excludedUrls: /user/login,/user/loginVerification,/system/users/verification,/system/users/login
@Component
public class AuthFilter implements GlobalFilter, Ordered {//排除的链接@Value("#{'${gateway.excludedUrls}'.split(',')}")private List excludedUrls;@Overridepublic Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {String url = exchange.getRequest().getURI().getPath();System.out.println( "url:"+ url);//排除特殊接口 不校验if(excludedUrls.contains(url)){return chain.filter(exchange);}String token = exchange.getRequest().getHeaders().getFirst("Authorization");if(!StringUtils.isEmpty(token)){token = token.replace("Bearer ", "");}ServerHttpResponse response = exchange.getResponse();//2、使用工具类,判断token是否有效boolean verifyToken = JwtUtils.verifyToken(token);//3、如果token失效,返回状态码401,拦截if(!verifyToken) {Map responseData = new HashMap<>();responseData.put("errCode", 401);responseData.put("errMessage", "用户未登录");return responseError(response,responseData);}return chain.filter(exchange);}//响应错误数据private Mono responseError(ServerHttpResponse response,Map responseData){// 将信息转换为 JSONObjectMapper objectMapper = new ObjectMapper();byte[] data = new byte[0];try {data = objectMapper.writeValueAsBytes(responseData);} catch (JsonProcessingException e) {e.printStackTrace();}// 输出错误信息到页面DataBuffer buffer = response.bufferFactory().wrap(data);response.setStatusCode(HttpStatus.UNAUTHORIZED);response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");return response.writeWith(Mono.just(buffer));}/*** 设置过滤器的执行顺序*/@Overridepublic int getOrder() {return Ordered.LOWEST_PRECEDENCE;}
}
Nacos提供了注册中心和配置管理的能力,使用Nacos可以快速实现服务发现、服务配置管理等需求
com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config
server:port: 8888
spring:profiles:active: prodapplication:name: tanhua-gatewaycloud:nacos:discovery:server-addr: 192.168.136.160:8848config:server-addr: 192.168.136.160:8848file-extension: yml
server:port: 9997
spring:cloud:gateway:globalcors:add-to-simple-url-handler-mapping: truecorsConfigurations:'[/**]':allowedHeaders: "*"allowedOrigins: "*"allowedMethods:- GET- POST- DELETE- PUT- OPTIONroutes:# 用户微服务- id: tanhua-app-serveruri: lb://tanhua-app-serverpredicates:- Path=/app/**filters:- StripPrefix= 1# 文章微服务- id: tanhua-adminuri: lb://tanhua-adminpredicates:- Path=/admin/**filters:- StripPrefix= 1
gateway:excludedUrls: /user/login,/user/loginVerification,/system/users/verification,/system/users/login
探花交友APP建立的后台管理系统,目的是完成探花交友项目的业务闭环,主要功能包括:用户管理、动态管理、审核管理以及系统管理。
课程中实现的功能有:登录、首页、用户管理、动态审核。
将资料中的tanhua-admin.sql
引入到mysql数据库中
后台系统也是采用前后端分离的方式,前端采用Vue.js实现,关于前端系统我们不进行实现,拿来直接使用。
将资料中提供的nginx解压到合适的位置
其中html目录中为,vue编译后的所有页面。
修改Nginx的/conf/nginx.conf
配置文件:
server {listen 8088; #请求端口server_name localhost;#charset koi8-r;#access_log logs/host.access.log main;location / {root html;index index.html index.htm;}location /management {proxy_pass http://127.0.0.1:18083/; #转发后台地址}#....略}
双击nginx.exe
,待启动完成后访问:http://127.0.0.1:8088即可访问后台项目
//后台系统的管理员对象
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Admin implements Serializable {/*** id*/private Long id;/*** 用户名*/private String username;/*** 密码*/private String password;/*** 头像*/private String avatar;
}
将今日资料中的tanhua-admin模块导入到探花项目中,完成开发。
DataID:tanhua-admin-prod.yml
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/tanhua-admin?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=falseusername: rootpassword: rootrabbitmq:host: 192.168.136.160port: 5672username: guestpassword: guest redis:host: 192.168.136.160port: 6379cloud: #nacos配置nacos:discovery:server-addr: 192.168.136.160:8848
dubbo: #dubbo配置registry:address: spring-cloud://localhostconsumer:check: falseretries: 0protocols:dubbo:port: -1#配置短信平台信息
tanhua: #手机验证码,咱们自己注册(不要白嫖)sms:signName: 物流云商templateCode: SMS_106590012accessKey: LTAI4GKgob9vZ53k2SZdyAC7secret: LHLBvXmILRoyw0niRSBuXBZewQ30laoss:accessKey: LTAI4GKgob9vZ53k2SZdyAC7secret: LHLBvXmILRoyw0niRSBuXBZewQ30laendpoint: oss-cn-beijing.aliyuncs.combucketName: tanhua143url: https://tanhua143.oss-cn-beijing.aliyuncs.comaip:appId: 22837663apiKey: nA43galrxfUZTGtYRVK8F8tbsecretKey: MQp567q4nGnIKfniURa2XAw8bT1SlPE3huanxin:appkey: 1110201018107234#tanhuaclientId: YXA6nxJJ_pdEQ_eYUlqcRicS4wclientSecret: YXA6GMUxVEZhAvxlMn4OvHSXbWuEUTE
#mybaits-plus
mybatis-plus:global-config:db-config:table-prefix: tb_ #数据库表前缀id-type: auto #数据库表主键的策略
后台系统的登录模块独立于APP端的登录。
验证码:页面端发送请求到服务端。服务端生成一个验证码的图片,已流的形式返回
/*** 生成图片验证码*/
@GetMapping("/verification")
public void verification(String uuid, HttpServletResponse response) throws IOException {//设置响应参数response.setDateHeader("Expires", 0);// Set standard HTTP/1.1 no-cache headers.response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");// Set IE extended HTTP/1.1 no-cache headers (use addHeader).response.addHeader("Cache-Control", "post-check=0, pre-check=0");// Set standard HTTP/1.0 no-cache header.response.setHeader("Pragma", "no-cache");response.setContentType("image/jpeg");//1、通过工具类生成验证码对象(图片数据和验证码信息)LineCaptcha captcha = CaptchaUtil.createLineCaptcha(299, 97);String code = captcha.getCode(); //1234//2、调用service,将验证码存入到redisredisTemplate.opsForValue().set(Constants.CAP_CODE+uuid,code);//3、通过输出流输出验证码captcha.write(response.getOutputStream());
}
/*** 用户登录:*/
@PostMapping("/login")
public ResponseEntity login(@RequestBody Map map) {Map retMap = adminService.login(map);return ResponseEntity.ok(retMap);
}
//用户登录
public ResponseEntity login(Map map) {//1、获取请求的参数(username,password,verificationCode(验证码),uuid)String username = (String) map.get("username");String password = (String) map.get("password");String verificationCode = (String) map.get("verificationCode");String uuid = (String) map.get("uuid");//2、判断用户名或者密码是否为空if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {//用户名或者密码为空//throw new BusinessException("用户名或者密码为空");Map map1 = new HashMap();map.put("message","用户名或者密码为空");return ResponseEntity.status(500).body(map1);}//3、判断验证码是否正确if (StringUtils.isEmpty(username)) {//验证码为空throw new BusinessException("验证码为空");}//从redis中获取验证码String key = Constants.CAP_CODE+uuid;String code = redisTemplate.opsForValue().get(key);if (StringUtils.isEmpty(code) || !code.equals(verificationCode)) {//验证码错误throw new BusinessException("验证码错误");}redisTemplate.delete(key);//4、根据用户名查询用户QueryWrapper qw = new QueryWrapper<>();qw.eq("username", username);Admin admin = adminMapper.selectOne(qw);//5、判断用户是否存在,密码是否一致password = SecureUtil.md5(password); //md5加密if(admin == null || !admin.getPassword().equals(password)) {//用户名错误或者密码不一致throw new BusinessException("用户名或者密码");}//6、通过JWT生成tokenMap claims = new HashMap();claims.put("username", username);claims.put("id", admin.getId());String token = JwtUtils.getToken(claims);//8、构造返回值Map res = new HashMap();res.put("token", token);return ResponseEntity.ok(res);
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AdminVo {/*** id*/private String id;/*** 用户名*/private String username;/*** 头像*/private String avatar;public static AdminVo init(Admin admin) {AdminVo vo = new AdminVo();vo.setAvatar(admin.getAvatar());vo.setUsername(admin.getUsername());vo.setId(admin.getId().toString());return vo;}}
/*** 获取用户的信息*/
@PostMapping("/profile")
public ResponseEntity profile() {AdminVo vo = adminService.profile();return ResponseEntity.ok(vo);
}
//获取当前用户的用户资料
public AdminVo profile() {Long id = AdminHolder.getId();Admin admin = adminMapper.selectById(id);return AdminVo.init(admin);
}
用户管理:对探花交友客户端注册用户的管理(查询业务数据),使用Dubbo的形式调用tanhua-dubbo-service获取响应的数据结果
@GetMapping("/users")
public ResponseEntity users(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pagesize) {PageResult result = managerService.findAllUsers(page,pagesize);return ResponseEntity.ok(result);
}
public ResponseEntity findAllUsers(Integer page, Integer pagesize) {//1、调用API分页查询数据列表 IpageIPage iPage = userInfoApi.findAll(page,pagesize);//2、需要将Ipage转化为PageResultPageResult result = new PageResult(page, pagesize, iPage.getTotal(), iPage.getRecords());//3、构造返回值return ResponseEntity.ok(result);
}
@Override
public IPage findAll(Integer page, Integer pagesize) {return userInfoMapper.selectPage(new Page(page,pagesize),null);
}
/*** 根据id查询用户详情*/
@GetMapping("/users/{userId}")
public ResponseEntity findById(@PathVariable("userId") Long userId) {return managerService.findById(userId);
}
//根据id查询用户详情
public ResponseEntity findById(Long userId) {UserInfo info = userInfoApi.findById(userId);return ResponseEntity.ok(info);
}
/*** 查询指定用户发布的所有视频列表*/
@GetMapping("/videos")
public ResponseEntity videos(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pagesize,Long uid ) {PageResult result = managerService.findAllVideos(page,pagesize,uid);return ResponseEntity.ok(result)
}
//根据用户id分页查询此用户发布的所有视频列表
public PageResult findAllVideos(Integer page, Integer pagesize, Long userId) {//1、调用API查询视频列表(PageResult
@GetMapping("/messages")
public ResponseEntity messages(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pagesize,Long uid,Integer state ) {PageResult result = managerService.findAllMovements(page,pagesize,uid,state);return ResponseEntity.ok(result)
}
//查询指定用户发布的所有动态
public ResponseEntity findAllMovements(Integer page, Integer pagesize, Long userId, Integer state) {//1、调用API查询 :(PageResult)PageResult result = movementApi.findByUserId(userId,page,pagesize);//2、一个Publsh构造一个MovementsList items = ( List)result.getItems();List list = new ArrayList<>();for (Movement item : items) {UserInfo userInfo = userInfoApi.findById(item.getUserId());MovementsVo vo = MovementsVo.init(userInfo, item);list.add(vo);}//3、构造返回值result.setItems(list);return ResponseEntity.ok(result);
}
上一篇:脚本语言Bash简明教程【1】
下一篇:C#学习笔记一 委托、事件