Skip to content
当前页

二开说明

开发规范

建表规范

建表规范

数据库建表建议添加下面,因为框架中自动生成代码entity会继承BaseEntity对象,BaseEntity默认包含下面属性。

字段名字段类型字段描述
id自定义唯一ID
create_byvarchar(50)创建用户
create_timedatetime创建时间
update_byvarchar(50)更新用户
update_timedatetime更新时间
java
//BaseEntity.java
@Data
@Accessors(chain = true)
@ApiModel("基础对象")
public class BaseEntity<T> {
    @ApiModelProperty(value = "ID")
    private T id;
    @ApiModelProperty(value = "创建用户")
    private String createBy;
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "创建时间")
    private Date createTime;
    @ApiModelProperty(value = "更新者")
    private String updateBy;
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "更新时间")
    private Date updateTime;
}

接口返回

接口返回 Result

接口返回结果用包装,前端会分析Result返回code,进行相应的结果提示

Result属性:

java
@ApiModelProperty("是否成功")
private boolean success = true;
@ApiModelProperty("状态码")
private int code = Constants.SUCCESS;
@ApiModelProperty("返回内容")
private String msg;
@ApiModelProperty("数据对象")
private T data;

返回结果样例:

java
@ApiOperation("界面配置-通过token查询")
@GetMapping
public Result<SysConfig> queryConfig() {
    SysConfig sysConfig = sysConfigService.querySysConfig(AuthInfoUtils.getCurrentUserId());
    return Result.ok(sysConfig, "界面配置-查询成功!");
}

分页查询

分页查询

分页查询结果用包装

  • 1、参数中增加ReqPage
  • 2、使用PageHelper.startPage进行分页启动
  • 3、使用PageResult进行分页包装
  • 4、最后进行Result结果包装返回
java
@ApiOperation(value = "字典-分页列表查询", notes = "字典-分页列表查询")
@GetMapping
@RequiresPermissions("sys:dict:query")
public Result<PageResult<Dict>> queryPageList(ReqDict reqDict, ReqPage reqPage) {
    PageHelper.startPage(reqPage.getPageNum(), reqPage.getPageSize());
    LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<Dict>()
            .like(reqDict.getDictCode() != null, Dict::getDictCode, reqDict.getDictCode())
            .like(reqDict.getDictName() != null, Dict::getDictName, reqDict.getDictName())
            .eq(reqDict.getStatus() != null, Dict::getStatus, reqDict.getStatus())
            .orderByDesc(true, Dict::getCreateTime);
    return Result.ok(new PageResult<>(dictService.list(queryWrapper)), "字典-查询成功!");
}

接口权限

接口权限

需要控制权限的接口可以通过在接口上面增加注解来自动拦截校验

单个权限样例:

java
@ApiOperation(value = "菜单表-分页列表查询", notes = "菜单表-分页列表查询")
@GetMapping
@RequiresPermissions("sys:menu:query")
public Result<List<SsoMenu>> queryList(ReqSsoMenu reqSsoMenu) {
    return queryMenu(reqSsoMenu, null);
}

多个权限样例:(Logical支持AND,OR)

java
@ApiOperation(value = "角色信息表-列表查询", notes = "角色信息表-列表查询")
@GetMapping("/all")
@RequiresPermissions(value = {"sys:role:query", "sys:account:query"}, logical = Logical.OR)
public Result<List<SsoRole>> queryList(ReqSsoRole reqSsoRole) {
    return Result.ok(ssoRoleService.list(buildCondition(reqSsoRole)), "角色信息表-查询成功!");
}

RequiresPermissions定义:

java
//RequiresPermissions.java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequiresPermissions {
    String[] value();

    Logical logical() default Logical.AND;
}

常用方法

获取用户id、token

获取当前帐号、用户ID等

可以通过获取当前帐号、用户ID、Token、判断是否超户等

注意

AuthInfoUtils方法只能在主线程中获取,如果需要在其他线程中获取需要先在主线程中获取后再将信息作为参数传入

获取用户ID样例:

java
@ApiOperation("界面配置-通过token查询")
@GetMapping
public Result<SysConfig> queryConfig() {
    SysConfig sysConfig = sysConfigService.querySysConfig(AuthInfoUtils.getCurrentUserId());
    return Result.ok(sysConfig, "界面配置-查询成功!");
}

获取token样例:

java
/**
 * 校验不同类型request中包含的token信息是否正确
 *
 * @param request
 * @param result  如果result已存在结果不再校验
 * @param <R>
 * @return
 */
public <R> Result<T> validateT(R request, Result<T> result) {
    if (result == null || result.getData() == null) {
        String accessToken = AuthInfoUtils.getAccessToken(request);
        return validate(accessToken);
    }
    return result;
}

获取当前账号样例:

java
@Override
public Object intercept(Invocation invocation) throws Throwable {
    BaseEntity parameter = getParameter(invocation);
    if (parameter == null) {
        return invocation.proceed();
    }
    //不支持异步调用获取当前帐号
    String account = AuthInfoUtils.getCurrentAccount();
    MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
    SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
    switch (sqlCommandType) {
        case INSERT:
            if (!StringUtils.isEmpty(account)) {
                parameter.setCreateBy(account);
            }
            parameter.setCreateTime(new Date());
            break;
        case UPDATE:
            if (!StringUtils.isEmpty(account)) {
                parameter.setUpdateBy(account);
            }
            parameter.setUpdateTime(new Date());
            break;
    }
    return invocation.proceed();
}

获取用户信息、角色、权限、判断是否有权限

获取当前用户

可以通过获取当前用户信息、角色、权限等

获取用户

java
public static UserInfo getUser() {
    RemoteUserService remoteUserService = getUserService();
    Result<UserInfo> result = remoteUserService.getUserById(RPCConstants.INNER, AuthInfoUtils.getCurrentUserId());
    if (result == null || !result.isSuccess()) {
        return null;
    }
    return result.getData();
}

获取角色

java
public static List<UserRole> getRoles() {
    RemoteUserService remoteUserService = getUserService();
    Result<List<UserRole>> result = remoteUserService.getRoles(RPCConstants.INNER, AuthInfoUtils.getCurrentUserId(), AuthInfoUtils.getCurrentClientId());
    if (result == null || !result.isSuccess()) {
        return null;
    }
    return result.getData();
}

获取权限

java
public static Set<String> getPermission() {
    RemoteUserService remoteUserService = getUserService();
    Result<Set<String>> result = remoteUserService.getPermissions(RPCConstants.INNER, AuthInfoUtils.getCurrentUserId(), AuthInfoUtils.getCurrentClientId());
    if (result == null || !result.isSuccess()) {
        return null;
    }
    return result.getData();
}

通过工厂获取bean

通过工厂获取bean

可以通过获取SpringBean进行对象创建

什么时候会用到?如果你需要在静态方法中调用spring中的对象,可能需要用到这个。

获取bean样例:

java
@Component("userRoleCache")
public class UserRoleCache extends BaseTempCache<List<UserRole>> {
...
}

/**
 * 校验角色
 *
 * @param requiresRoles 角色限制
 * @return
 */
public static boolean checkRoles(RequiresRoles requiresRoles) {
    UserRoleCache userRoleCache = SpringBeanFactory.getBean("userRoleCache");
    List<UserRole> list = userRoleCache.getFromCacheAndDB(AuthInfoUtils.getCurrentUserId(), AuthInfoUtils.getCurrentClientId());
    Set<String> set = list.stream().map(UserRole::getRoleCode).collect(Collectors.toSet());
    //如果用户为超户,直接返回
    if (null != set && set.contains(SerConstant.SUPER_ROLE)) {
        return true;
    }
    return checkValue(requiresRoles.logical(), requiresRoles.value(), set);
}

调用外部http接口

调用外部http接口

可以通过调用外部http接口,提供了GET,POST,UPLOAD方法,支持HTTPS

调用chatGpt样例:

java
public static Result answerMyQuestion(String url, String token, String ask_string) throws IOException {
    Completion openAi = new Completion();
    //添加我们需要输入的内容
    openAi.setModel("text-davinci-003");
    openAi.setPrompt(ask_string);
    openAi.setTemperature(0.7);
    openAi.setMax_tokens(2048);
    openAi.setTop_p(1);
    openAi.setFrequency_penalty(0);
    openAi.setPresence_penalty(0);
    Map<String, String> map = new HashMap<>();
    map.put("Authorization", "Bearer " + token);
    return OkHttpUtils.postJson(url, JSON.toJSONString(openAi), map, new OkHttpUtils.TimeOut().setTimeUnit(TimeUnit.MINUTES));
}

增加模块

增加Web服务

新增web服务

建议在模块下新建自己的业务模块,参考mf-web

  • 1、新建maven module

  • 2、pom中引入mf-common-web

    说明

    如果需要连接数据库引入数据库驱动,下面样例引入了mysql驱动

    xml
    <dependencies>
        <!-- Mysql Connector -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.com.mfish</groupId>
            <artifactId>mf-common-web</artifactId>
        </dependency>
    </dependencies>
  • 3、增加日志配置logback-logstash.xml

    日志配置

  • 4、增加nacos连接配置bootstrap.yml

    nacos连接配置

  • 5、增加启动类

    说明

    创建启动类并增加@AutoWeb注解即可

    java
    @Slf4j
    @AutoWeb
    public class MfWebApplication {
    public static void main(String[] args) {
    SpringApplication.run(MfWebApplication.class, args);
    log.info("\n\t----------------------------------------------------------\n\t" +
    "\n\t--------------------摸鱼其他web业务服务启动成功-----------------------\n\t");
    }
    }
  • 6、增加nacos配置

    说明

    开发环境在nacos中创建${应用名称}-dev.yml,并增加数据库配置即可

    参考配置

  • 7、在网关配中增加路由条件

    说明

    需要增加网关路由后,才能够通过网关访问服务接口,否则只能直接访问具体服务

    ${应用名称}:对应nacos连接配置中应用名称

    ${接口路径前缀}:对应代码生成功能中的接口路径前缀

    yml
    routes:
      - id: ${应用名称}
        uri: lb://${应用名称}
        predicates:
          - Path=/${接口路径前缀}/**
        filters:
            - StripPrefix=1

增加Feign接口

模块中增加对应的api模块,增加对应的Feign调用接口和失败处理逻辑。

@RequestHeader(RPCConstants.REQ_ORIGIN) String origin参数解析

该参数标识接口是否内部调用,某些内部接口通过标识后,可以限制只允许内部服务访问,防止外部服务通过http接口直接访问。

Feign接口样例代码:

java
//contextId保持唯一
//value与应用名称对应
//fallbackFactory 为失败处理类
//@PostMapping("/sysLog")与实际接口保持一致
@FeignClient(contextId = "remoteLogService", value = ServiceConstants.SYS_SERVICE, fallbackFactory = RemoteLogFallback.class)
public interface RemoteLogService {
    @PostMapping("/sysLog")
    Result<SysLog> addLog(@RequestHeader(RPCConstants.REQ_ORIGIN) String origin, @RequestBody SysLog sysLog);
}

失败处理样例代码:

java
@Slf4j
@Component
public class RemoteLogFallback implements FallbackFactory<RemoteLogService> {
    @Override
    public RemoteLogService create(Throwable cause) {
        log.error("错误:日志服务调用异常", cause);
        return (origin, sysLog) -> Result.fail("错误:新增日志失败");
    }
}

增加业务代码

代码生成

配置说明

登录互斥

进入nacos配置界面,在mf-oauth-dev.yml配置中,找到

yml
oauth2:
  expire:
    code: 180
    token: 21600
    refreshToken: 604800
  login:
    mutex: false
  user:
    autoCreate: false

将mutex修改为true,即打开了登录互斥功能。

提示

互斥打开后,一个帐号同类型设备只允许在一处登录,在其他地方登录会踢出之前登录的帐号。

互斥规则:

同一个帐号,允许同时登录手机,微信,浏览器

同一个帐号只允许在一个手机,一个微信,一个浏览器上登录

账号自动注册

进入nacos配置界面,在mf-oauth-dev.yml配置中,找到

yml
oauth2:
  expire:
    code: 180
    token: 21600
    refreshToken: 604800
  login:
    mutex: false
  user:
    autoCreate: false

将autoCreate修改为true,即打开了自动注册帐号功能。

注意

该功能只有当微信登录或者短信验证码登录时,允许自动创建帐号