前言
okey,现在的话。我们来看到后端的代码编写。首先的话,这里本来是打算使用ruoyiCloud版本的。但是发现,用rouyi的话,在我的这个项目里面自由度太低了。主要问题就在于,我们后面有两台系统,一个是中台系统,一个是我们的博客系统。博客系统是对外提供服务的,同时也是中台系统的一个下游系统。直接使用ruoyi的话,对于下游服务调用的话是比较友好的,因为我们都知道ruoyi的权限分为外权限,和内权限,服务间的调用属于内权限。但是对于外权限来说,这个就麻烦了。因为我们这里两个系统是使用的不同的用户数据库的。也就是说验证是不同的,而且,说实话,我只是需要一个中台系统而已。但是很抱歉木有找到合适的,于是只能继续使用人人开源。所以这里我们这里需要解决的问题是:两个系统的交互
基本架构
这里的话我们就不来虚的了,我们先直接看到我们的这个项目的目录: 当然这里还有个模块,就是我们的博客系统的业务模块。这里的话,暂时还没有动,今天只是建表,做个简单的项目构建。 然后我们的一个整合之后的后台系统就长这样:
内部服务
okey,之后的话,我们来看到这个内部的一个服务调用,也就是这块:
那么在这里的话,我是这样处理的,这里首先主要处理的是服务之间api的一个调用。也就是只验证,这个服务的一个合法性。这一点和若依是很像的。只是验证的方式可能不一样。 我们的基本流程是这样的:
基本整合
okey,现在我们来看到基本的这个是怎么整合的。 我们先进入项目地址:github.com/renrenio/
这个项目里面的话是有好几个项目的,这里简单介绍一下。
renren-fast-vue
这个玩意是一套后端的管理系统,很多东西也是构建好了的,拿来用,改一下配就好了。那么这个是前后端分离的一个前端项目,是基于vue+elementui 做的。
renren-fast
这个是和咱们fast-vue配套的后端
其他的官网都有介绍。我这里就挑几个来look,look。
那么咱们这里还有使用到的呢就是 renren-generator 也就是咱们的代码生成器。
环境准备
现在我们已经有了数据库,表啥的都建好了。
那么我们下载好源码
当然,在整合到项目之后,我改了个名字: geberator是对应的生成器。这个我们明天权限整合的时候会用到,之后这个做好了之后的话,我们把netty消息模块做好,以及用户系统做好,那么我们就差不多了。就差个推荐系统了。
common包
那么在这里的话,主要还是注意到common包的整合。
这里面有必要的,人人开源需要运行的类。我单独抽离出来了,因为后面生成的代码也需要这个东西才能正常运行。
那么现在我就依次把对应的代码给出了,自己创建好后,复制就好了。
exception
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.exception;
/**
* 自定义异常
*
* @author Mark sunlightcs@gmail.com
*/
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public RRException(String msg) {
super(msg);
this.msg = msg;
}
public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
utils
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
* <p>
* https://www.renren.io
* <p>
* 版权所有,侵权必究!
*/
package com.huterox.common.utils;
import com.huterox.common.validator.group.AliyunGroup;
import com.huterox.common.validator.group.QcloudGroup;
import com.huterox.common.validator.group.QiniuGroup;
import java.util.Optional;
import java.util.stream.Stream;
/**
* 常量
*
* @author Mark sunlightcs@gmail.com
*/
public class Constant {
/**
* 超级管理员ID
*/
public static final int SUPER_ADMIN = 1;
/**
* 当前页码
*/
public static final String PAGE = "page";
/**
* 每页显示记录数
*/
public static final String LIMIT = "limit";
/**
* 排序字段
*/
public static final String ORDER_FIELD = "sidx";
/**
* 排序方式
*/
public static final String ORDER = "order";
/**
* 升序
*/
public static final String ASC = "asc";
/**
* 菜单类型
*
* @author chenshun
* @email sunlightcs@gmail.com
* @date 2016年11月15日 下午1:24:29
*/
public enum MenuType {
/**
* 目录
*/
CATALOG(0),
/**
* 菜单
*/
MENU(1),
/**
* 按钮
*/
BUTTON(2);
private int value;
MenuType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
/**
* 定时任务状态
*
* @author chenshun
* @email sunlightcs@gmail.com
* @date 2016年12月3日 上午12:07:22
*/
public enum ScheduleStatus {
/**
* 正常
*/
NORMAL(0),
/**
* 暂停
*/
PAUSE(1);
private int value;
ScheduleStatus(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
/**
* 云服务商
*/
public enum CloudService {
/**
* 七牛云
*/
QINIU(1, QiniuGroup.class),
/**
* 阿里云
*/
ALIYUN(2, AliyunGroup.class),
/**
* 腾讯云
*/
QCLOUD(3, QcloudGroup.class);
private int value;
private Class<?> validatorGroupClass;
CloudService(int value, Class<?> validatorGroupClass) {
this.value = value;
this.validatorGroupClass = validatorGroupClass;
}
public int getValue() {
return value;
}
public Class<?> getValidatorGroupClass() {
return this.validatorGroupClass;
}
public static CloudService getByValue(Integer value) {
Optional<CloudService> first = Stream.of(CloudService.values()).filter(cs -> value.equals(cs.value)).findFirst();
if (!first.isPresent()) {
throw new IllegalArgumentException("非法的枚举值:" + value);
}
return first.get();
}
}
}
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.utils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.List;
/**
* 分页工具类
*
* @author Mark sunlightcs@gmail.com
*/
public class PageUtils implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 总记录数
*/
private int totalCount;
/**
* 每页记录数
*/
private int pageSize;
/**
* 总页数
*/
private int totalPage;
/**
* 当前页数
*/
private int currPage;
/**
* 列表数据
*/
private List<?> list;
/**
* 分页
* @param list 列表数据
* @param totalCount 总记录数
* @param pageSize 每页记录数
* @param currPage 当前页数
*/
public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
this.list = list;
this.totalCount = totalCount;
this.pageSize = pageSize;
this.currPage = currPage;
this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
}
/**
* 分页
*/
public PageUtils(IPage<?> page) {
this.list = page.getRecords();
this.totalCount = (int)page.getTotal();
this.pageSize = (int)page.getSize();
this.currPage = (int)page.getCurrent();
this.totalPage = (int)page.getPages();
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getCurrPage() {
return currPage;
}
public void setCurrPage(int currPage) {
this.currPage = currPage;
}
public List<?> getList() {
return list;
}
public void setList(List<?> list) {
this.list = list;
}
}
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.utils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.huterox.common.xss.SQLFilter;
import org.apache.commons.lang.StringUtils;
import java.util.Map;
/**
* 查询参数
*
* @author Mark sunlightcs@gmail.com
*/
public class Query<T> {
public IPage<T> getPage(Map<String, Object> params) {
return this.getPage(params, null, false);
}
public IPage<T> getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) {
//分页参数
long curPage = 1;
long limit = 10;
if(params.get(Constant.PAGE) != null){
curPage = Long.parseLong((String)params.get(Constant.PAGE));
}
if(params.get(Constant.LIMIT) != null){
limit = Long.parseLong((String)params.get(Constant.LIMIT));
}
//分页对象
Page<T> page = new Page<T>(curPage, limit);
//分页参数
params.put(Constant.PAGE, page);
//排序字段
//防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
String orderField = SQLFilter.sqlInject((String)params.get(Constant.ORDER_FIELD));
String order = (String)params.get(Constant.ORDER);
//前端字段排序
if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){
if(Constant.ASC.equalsIgnoreCase(order)) {
return page.addOrder(OrderItem.asc(orderField));
}else {
return page.addOrder(OrderItem.desc(orderField));
}
}
//没有排序字段,则不排序
if(StringUtils.isBlank(defaultOrderField)){
return page;
}
//默认排序
if(isAsc) {
page.addOrder(OrderItem.asc(defaultOrderField));
}else {
page.addOrder(OrderItem.desc(defaultOrderField));
}
return page;
}
}
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.utils;
import org.apache.http.HttpStatus;
import java.util.HashMap;
import java.util.Map;
/**
* 返回数据
*
* @author Mark sunlightcs@gmail.com
*/
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", 0);
put("msg", "success");
}
public static R error() {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
}
public static R error(String msg) {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
}
validator
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 新增数据 Group
*
* @author Mark sunlightcs@gmail.com
*/
public interface AddGroup {
}
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 阿里云
*
* @author Mark sunlightcs@gmail.com
*/
public interface AliyunGroup {
}
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
import javax.validation.GroupSequence;
/**
* 定义校验顺序,如果AddGroup组失败,则UpdateGroup组不会再校验
*
* @author Mark sunlightcs@gmail.com
*/
@GroupSequence({AddGroup.class, UpdateGroup.class})
public interface Group {
}
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 腾讯云
*
* @author Mark sunlightcs@gmail.com
*/
public interface QcloudGroup {
}
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 七牛
*
* @author Mark sunlightcs@gmail.com
*/
public interface QiniuGroup {
}
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.validator.group;
/**
* 更新数据 Group
*
* @author Mark sunlightcs@gmail.com
*/
public interface UpdateGroup {
}
xxs
java
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.huterox.common.xss;
import com.huterox.common.exception.RRException;
import org.apache.commons.lang.StringUtils;
/**
* SQL过滤
*
* @author Mark sunlightcs@gmail.com
*/
public class SQLFilter {
/**
* SQL注入过滤
* @param str 待验证的字符串
*/
public static String sqlInject(String str){
if(StringUtils.isBlank(str)){
return null;
}
//去掉'|"|;|\字符
str = StringUtils.replace(str, "'", "");
str = StringUtils.replace(str, "\"", "");
str = StringUtils.replace(str, ";", "");
str = StringUtils.replace(str, "\\", "");
//转换成小写
str = str.toLowerCase();
//非法字符
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};
//判断是否包含非法字符
for(String keyword : keywords){
if(str.indexOf(keyword) != -1){
throw new RRException("包含非法字符");
}
}
return str;
}
}
之后的话,那么这个就搞定了,然后给需要的模块就好了。当然这个主要还是给代码生成器生成的代码模块用的。你这样做之后,就可以直接导入了。例如这样:
当然,这里的common我还做了其他的工作,只是,如果你单独需要跑的话,不需要这样。我这块需要。
微服务整合
okey,然后我们要做的就是整合到微服务里面。
首先最外面我创建了一个父工程
html
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.huterox.hlang</groupId>
<artifactId>HlangCloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HlangCloud</name>
<description>父工程</description>
<packaging>pom</packaging>
<modules>
<module>hlang-admin</module>
<module>hlang-gateway</module>
<module>hlang-common</module>
</modules>
</project>
然后创建网关:
这里别忘了导入依赖。 以我这个为例,是这样的:
html
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.huterox.whitehole</groupId>
<artifactId>hlang-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>hlang-gateway</name>
<description>hlang-gateway</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependencies>
<!-- 这个gateway我们就单独导入了,因为只有一个-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.huterox.hlangService.common</groupId>
<artifactId>hlang_common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</exclusion>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
跨域
然后是跨域的问题,这里的话,注意人人开源这里的话,有跨域处理。所以要注释掉这里的。 然后在网关处理:
java
package com.huterox.hlang.hlangGateWay.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 HlangCorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
//设置预检请求的缓存时间(秒),在这个时间段里,对于相同的跨域请求不会再预检了
config.setMaxAge(18000L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
之后的话,就是前端的一些处理了,这个没啥。
总结
okey,今天就到这里了,我们接下来处理好其他的模块。争取在20号去实习之前完成基本的项目开发。然后后面就"磨洋工了"