快速开发平台 fast_security_admin:SpringBoot+Mybatis-Plus+反射 通用开发接口

Posted liu++

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快速开发平台 fast_security_admin:SpringBoot+Mybatis-Plus+反射 通用开发接口相关的知识,希望对你有一定的参考价值。

快速开发平台 fast_security_admin(一):SpringBoot+Mybatis-Plus+反射 通用开发接口

fast_security_admin在gitee地址

需求提出

之前使用mybatis每个实体类都要写getAll()、getById()、update()、save()、remove(),有大量重复代码,那么用了mybatis-plus好一些不用写重复的sql了,但是还要写重复的service、controller以及前端页面

解决方案(思路)

第一步就是写通用接口,也就是本篇博客介绍的内容,通过传入字符串调用哪个Entity的Service,由于使用了Mybatis-plus每个Service都有list()、getById()、remove(),这就使实现成为可能,在后面会介绍错误或者说不好的思路。

第二步,数据库创建一个表头表,以及菜单表,在下一篇博客介绍。

第三步,前端vue组件开发,所有的数据都动态的。

暂时没有图,以后做成了再回来补图片。

具体实现

目录结构

在这里插入图片描述

简单介绍一下,Fast**是本次重点类,其余的是demo,比如说UserAuths,换成User也一样。

demo是什么样的

以UserAuths为例

UserAuths实体类,使用mybatisplus标注@TableId

@Data
public class UserAuths implements Serializable {
    private static final long serialVersionUID=1L;
    @TableId(value = "user_id", type = IdType.AUTO)
    private Integer userId;
    private Integer identityTypeId;
    private String identifier;
    private String credential;
}

UserAuthsMapper,mybatisplus自动生成的暂时什么都不用动,以后需要自己写复杂sql,再在里面加方法,mapper的xml文件不展示了都是自动生成的。

@Repository
public interface UserAuthsMapper extends BaseMapper<UserAuths> {
}

UserAuthsService,同样是自动生成的,暂时不用动

public interface UserAuthsService extends IService<UserAuths>{
}

UserAuthsServiceImpl,同样是自动生成的,暂时不用动。

@Service
public class UserAuthsServiceImpl extends ServiceImpl<UserAuthsMapper, UserAuths> implements UserAuthsService {}

关键代码:Fast**

ServerResponse是统一返回vo封装。

FastService

public interface FastService {

    ServerResponse list(String entity) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;

    ServerResponse getById(String entity,Integer id) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException;

    ServerResponse removeById(String entity,Integer id) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;
}

重点FastServiceImpl

@Service
public class FastServiceImpl implements FastService {
    @Autowired
    private ApplicationContext applicationContext;
    //根据传入的字符串获取ServiceImpl的bean然后利用反射调用方法,因为是使用mybatis-plus所以里面咱们自己不写,它也有继承的方法。
    @Override
    public ServerResponse list(String entity) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object bean = applicationContext.getBean(entity + "ServiceImpl");
        Class<?> c = bean.getClass();
        Object list = c.getMethod("list").invoke(bean);
        return ServerResponse.succese(list);
    }

    @Override
    public ServerResponse getById(String entity, Integer id) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Object bean = applicationContext.getBean(entity + "ServiceImpl");
        Class<?> c = bean.getClass();
        Object getById = c.getMethod("getById", new Class[]{Serializable.class}).invoke(bean, id);
        return ServerResponse.succese(getById);
    }

    @Override
    public ServerResponse updateById(String entity, Object o) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object bean = applicationContext.getBean(entity + "ServiceImpl");
        Class<?> c = bean.getClass();
        c.getMethod("updateById", new Class[]{o.getClass()}).invoke(bean, o);
        return ServerResponse.succese();
    }

    @Override
    public ServerResponse save(String entity, Object o) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object bean = applicationContext.getBean(entity + "ServiceImpl");
        Class<?> c = bean.getClass();
        c.getMethod("updateById", new Class[]{o.getClass()}).invoke(bean, o);
        return ServerResponse.succese();
    }

    @Override
    public ServerResponse removeById(String entity, Integer id) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object bean = applicationContext.getBean(entity + "ServiceImpl");
        Class<?> c = bean.getClass();
        c.getMethod("removeById", new Class[]{Serializable.class}).invoke(bean, id);
        return ServerResponse.succese();
    }
}

因为在springboot里面,要用ApplicationContext获取bean,ApplicationContext这个还封装了一个工具类,如果感兴趣可以看我gitee。

FastController

@RestController
@RequestMapping("/fast")
public class FastController {
    @Autowired
    private FastService fastService;

    @GetMapping("list/{entity}")
    public ServerResponse list(@PathVariable("entity")String entity) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return fastService.list(entity);
    }

    @GetMapping("getById/{entity}/{id}")
    public ServerResponse getById(@PathVariable("entity")String entity,@PathVariable("id")Integer id) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return fastService.getById(entity,id);
    }

    @DeleteMapping("removeById/{entity}/{id}")
    public ServerResponse removeById(@PathVariable("entity")String entity,@PathVariable("id") Integer id) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return fastService.removeById(entity, id);
    }
}

很简单。

注意的问题

1.在springboot中或者说在spring中获取bean不要直接用Class.forName(name),这样获取不到,具体是为什么,百度,我之后肯定写一篇关于ApplicationContext的博客。

2.一定是在Server层开始封装,不要想着在mapper层封装,写动态sql,这样不行(不好),会面临两个问题,一个是动态表名必须${},会有sql注入的问题,再有就是动态返回值,这个还要封装工作量太大没必要,mybatis有这个动态返回值的插件,但是没必要,利用mybatis-plus就行了。

3.与Hibernate,不是很了解Hibernate,但是肯定是有所不同的,但是有点像,没必要纠结(个人不纠结哈哈)。为什么说像,这个肯定是在开发后台的时候用,在初期,快速搭建,后期如果性能没问题继续用在后台我是这样想的,据百度,Hibernate不行是因为扩展性太差,强耦合,目前的设想是做成多模块项目,应该还好,就是mybatisplus的耦合性,毕竟在下只是学生不做特别大的项目应该没事。

4.第一次设想把save和update也做了,但是用mybatis-plus提供的方法不行

ServerResponse updateById(String entity,Object o) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;

    ServerResponse save(String entity,Object o) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;

你save传入的参数必须是具体的实体类!!!object不行,想用反射,但是不行!!!你想获取实体类要在实体类加@Component注解这样应该会影响性能,并且获得了类也没用,将object转实体类这一步行不通!!!错误代码如下,以save为例。

@Override
    public ServerResponse save(String entity, Object o) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object bean = applicationContext.getBean(entity + "ServiceImpl");
        Class<?> c = bean.getClass();
        ObjectMapper objectMapper=new ObjectMapper();
        //转不了
        Object o1 = objectMapper.convertValue(o, applicationContext.getBean(entity).getClass());
        //如果不转,这一步不行
        c.getMethod("save", applicationContext.getBean(entity).getClass()).invoke(bean,o1);
        return ServerResponse.succese();
    }

那么有什么解决办法吗?当然有,可以用jdbc封装或者写mybatis也行(不是很方便传入参数类型没想好),但是这里jdbc简单一点,但是有sql注入的问题(虽然可以手写过滤器),传的参数也比较复杂,并且必要性不大

java使用JDBC动态save、update及SQL预处理的方法

我想写通用接口的一个重要目的是减少前端工作量,但是save界面(弹窗)很难统一,创一个记录各个表字段的表,但是统一save页面这样真的不是很方便,不方便在一些特殊字段date、上传文件,而且数据库字段名和实体类属性名不一样,比较乱,想自定义save页面没有办法,而且要是方便,早就有人做了,但是应该是可以的,就不实现了,也省事了。

存在的问题

1.性能问题,反射的性能,所有的请求都集中在这几个接口上不知道行不行,如果有大佬知道跪求解答。

2.耦合

3.异常处理

项目接下来计划

开头说了表头表,以及菜单表,前端动态组件,减少重复工作,以及集成权限管理RBAC!计划是5.25之前完成应该可以,淦。

以上是关于快速开发平台 fast_security_admin:SpringBoot+Mybatis-Plus+反射 通用开发接口的主要内容,如果未能解决你的问题,请参考以下文章

企业级快速开发平台哪家更好?

国内java快速开发平台有哪几家?

都用的啥erp系统快速开发平台?

快速开发平台的两种模式

免费的java快速开发平台都有哪些?

snf 快速开发平台 如何收费