对于常用 crud 的一些思考和设计 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
huifer
V2EX    Java

对于常用 crud 的一些思考和设计

  •  
  •   huifer 2020 年 8 月 31 日 2458 次点击
    这是一个创建于 2062 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Crud 项目介绍

    简化单表的 CRUD 基本代码.

    项目地址

    为什么使用

    • 比如学生管理系统.表设计有 课程表t_classes等等...在管理系统中我们需要添加课程的时候需要做一次 controller 、service 、redis 、dao 这几类操作. 每多一个表格都需要做这一批操作. 一般有新增、修改、删除、根据 id 查询.

      • 当使用了这个项目后通过标记一些注解即可获得上述的功能.

    假设现在有表格

    | 字段 |类型 | | ---- | ---- | | id | int | | name | varchar |

    常规实现

    1. 创建 controller 类
    2. 创建 service 类
    3. 创建 一些验证方法
    4. 组合起来
    @RestController @RequestMapping("/demo") public class ProjectDemoController { @Autowired private ProjectDemoMapper projectDemoMapper; @PostMapping("/add") public ResultO add( @RequestBody ProjectDemo req ) { int i = projectDemoMapper.insertSelective(req); if (i > 0) { return ResultVO.success(); } else { return ResultVO.failed(); } } } 
    • 省略验证方法, 省略 service 编写. 正常应该分一分.

    • 现在 只有数据库层面的交互代码我们可能还需要一个 redis 上的操作

      (hash 数据类型) 那么这部分代码还需要在写一次

      @RestController @RequestMapping("/demo") public class ProjectDemoController { @Autowired private ProjectDemoMapper projectDemoMapper; @Autowired private StringRedisTemplate stringRedisTemplate; @PostMapping("/add") public ResultVO add( @RequestBody ProjectDemo req ) { int i = projectDemoMapper.insertSelective(req); if (i > 0) { stringRedisTemplate.opsForHash() .put("demo", String.valueOf(req.getId()), JSON.toJSONString(req)); return ResultVO.success(); } else { return ResultVO.failed(); } } } 
      • 这部分代码出现的次数可能会随着实体类的增多而增多. 每当一个表出现上述的 CRUD 都需要在编辑以便代码. 很是繁琐 , 对此提出了一个设想.

    crud 实现

    省略 controller 的编写

    • 路径说明: /rest+ @CrudController#uri + add\editor\del\byId

    • 定义一个 实体对象

    @CrudController(uri = "/project/demo", idType = Integer.class) public class ProjectInt extends AbsEntity implements Serializable { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } 
    • 定义一个 mapper

      @Mapper @CacheKey(type = ProjectInt.class,key = "asdc") public interface ProjectIntMapper extends A<Integer, ProjectInt> { @Override @Insert("INSERT INTO `project_int`(`name`) VALUES (#{name} ) ") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") int insertSelective(ProjectInt record); @Override @Select("select * from project_int where id = #{id,javaType=INTEGER} ") ProjectInt selectByPrimaryKey(@Param("id") Integer integer); @Override @Delete("DELETE FROM `dest`.`project_int` WHERE `id` = #{id} ") int deleteByPrimaryKey(@Param("id") Integer integer); @Override @Update("UPDATE `dest`.`project_int` SET `name` = #{name} WHERE `id`= #{id} ") int updateByPrimaryKeySelective(ProjectInt record); } 
    • 注册 servlet

      @Bean ServletRegistrationBean myServletRegistration() { ServletRegistrationBean srb = new ServletRegistrationBean(); srb.setServlet(new OcaServlet()); srb.setUrlMappings(Arrays.asList("/rest/*")); return srb; } 
    • 权限验证:在使用了两个 servlet 后通过拦截器验证会有问题,请使用 filter 进行权限验证

    自定义入参验证

    • 自定义参数验证是不可避免的. 在这里提出一个接口com.github.huifer.crud.ctr.validated.ValidatedInterface
    • entityClass 填写对应的数据库对象即可
    @Service public class ProjectIntValidated implements ValidatedInterface<ProjectInt> { Gson gson = new Gson(); public Class<?> entityClass() { return ProjectInt.class; } public void validateDelete(ProjectInt projectInt) { System.out.println(gson.toJson(projectInt)); } public void validateAdd(ProjectInt projectInt) { System.out.println(gson.toJson(projectInt)); } public void validateById(ProjectInt projectInt) { System.out.println(gson.toJson(projectInt)); } public void validateEditor(ProjectInt projectInt) { System.out.println(gson.toJson(projectInt)); } } 
    • 如果验证不通过可以在这个方法中直接抛出异常.

    省略 mybatis + redis 编写

    • 有时我们需要直接调用普通的 crud 不需要从 controller 进行调用 。在这个前提下我们可以使用

    • 需要在 mapper 和 db 实体类进行标记

     public class IssuesEntity implements BaseEntity { private Integer id; private String newTitle; private Date date; } @Mapper @CacheKey(key = "issues", type = IssuesEntity.class) public interface IssuesMapper extends A<Integer, IssuesEntity> { @Insert(" insert into issue(new_title)values(#{newTitle,jdbcType=VARCHAR})") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") int insertSelective(IssuesEntity record); @Select("select id as id , new_title as newTitle from issue where id = #{integer} ") IssuesEntity selectByPrimaryKey(Integer integer); @Override @Update("UPDATE `issue` SET `new_title` = #{newTitle} WHERE `id` = #{id} ") int updateByPrimaryKeySelective(IssuesEntity record); @Override @Delete("delete from issue where id = #{integer}") int deleteByPrimaryKey(Integer integer); } 
    • 调用层代码
     @Autowired private CrudFacade<IssuesEntity, IntIdInterface<Integer>> crudFacade; @Test void testInsert() { IssuesEntity issuesEntity = new IssuesEntity(); issuesEntity.setNewTitle("mybatis_test"); crudFacade.insert(issuesEntity); } 
    • 使用后直接具有 db 操作和 redis 的操作

    省略 redis 编写

    • 有时对象可能直接存储在 redis 中而不是存储 db 。 在这个前提下可以使用

    • 类标记

    @CacheKey(key = "tt", type = IssuesEntity.class, idMethod = "ooo") public class IssuesEntity implements BaseEntity { private Integer id; private String newTitle; private Date date; } 
    • 调用层代码
    @Autowired private CrudEntityFacade<IssuesEntity> crudEntityFacade; @Test void testInsert() { IssuesEntity issuesEntity = new IssuesEntity(); issuesEntity.setNewTitle("insert"); issuesEntity.setDate(new Date()); crudEntityFacade.insert(issuesEntity); } 

    自定义 json 序列化规则

    • 目前只支持 gson 和 jackjson 两种

      • gson 自定实现: com.github.huifer.crud.common.conf.json.GsonConfigSetting
      • jackjson 自定义实现: com.github.huifer.crud.common.conf.json.JackJsonConfigSetting
    • 具体用例请查看: https://github.com/huifer/crud/tree/dev/simple-example

    注意

    目前 redis 仅支持 hash 操作

    欢迎各位提出意见 : https://github.com/huifer/crud/issues

    3 条回复    2020-08-31 15:44:15 +08:00
    yumenawei
        1
    yumenawei  
       2020 年 8 月 31 日
    OcaServlet 是个啥,没看到相关定义
    chendy
        2
    chendy  
       2020 年 8 月 31 日
    感谢分享
    东西一般
    huifer
        3
    huifer  
    OP
       2020 年 8 月 31 日
    @yumenawei 自定义的一个 servlet
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     901 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 39ms UTC 19:48 PVG 03:48 LAX 12:48 JFK 15:48
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86