sharp-database中的BaseDAOImpl使用指北

如何使用

BaseDAOImpl 的实现依赖于 SQLUtilsSharpService,主要是表的面向对象的CRUD操作。

让DAO继承 BaseDAOImpl。 实体对象继承BaseEntity

@SuperBuilder
@Getter
@Setter
@NoArgsConstructor
public class BaseEntity extends SimpleEntity {

    @Column(updatable = false)
    private Long createdBy;

    @Column(updatable = false)
    private Instant createdAt;

    private Long updatedBy;

    private Instant updatedAt;

    @Column(BaseEntityConstants.LOGIC_DELETE_COLUMN_NAME)
    private Boolean deleted;

}

`SimpleEntity.java`
```java
@SuperBuilder
@Getter
@Setter
@NoArgsConstructor
public class SimpleEntity {

    @Id
    @JsonSerialize(using = ToStringSerializer.class)
    private Long id;

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        if (obj instanceof SimpleEntity) {
            SimpleEntity dataEntity = (SimpleEntity)obj ;
            if (dataEntity.id != null && dataEntity.id.equals(id))
                return true;
        }

        return false;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
                .append(id).toHashCode();
    }
}

手动指定表名和字段(字段的顺序要和entity属性的定义的顺序相同)

@Repository
public class ProjectDAO extends BaseDAOImpl<Project> {

    public ProjectDAO() {
        super("t_project", "id,title,description,cover_url,owner_id,created_by,created_at,updated_by,updated_at,is_deleted", "id");
    }
}

使用注解自动识别(推荐)

@Repository
public class ProjectGroupDAO extends BaseDAOImpl<ProjectGroup> {
}

ProjectGroup.java

@TableName("t_project_group")
@Getter
@Setter
public class ProjectGroup extends BaseEntity {

    private String title;

    private Long parentId;

    @ColumnName("group_id")
    private Long groupId;
}

如果没有注解 @ColumnName ,默认列名为驼峰名转下划线;没有注解 @TableName 默认表名为驼峰名转下划线。@Transient不参与持久化;@Id主键标识。

不指定范型

@Repository
public class MapDAO extends BaseDAOImpl {

    public MapDAO() {
        super("t_project", "id,title,description,cover_url,owner_id,created_by,created_at,updated_by,updated_at,is_deleted", "id");
    }
}

跟指定范型的区别 select 返回的对象由范型的实体变成了 Map 接收。insert update不能处理对象参数。 等价于下面的代码:

@Repository
public class MapDAO extends BaseDAOImpl<Map> {

    public MapDAO() {
        super("t_project", "id,title,description,cover_url,owner_id,created_by,created_at,updated_by,updated_at,is_deleted", "id");
    }
}

测试

添加数据insert

  • 添加数据(数组参数)
public void insert(Object[] params)
@Test
public void testInsert() {
    // id,title,description,created_by,created_at,updated_by,updated_at,is_deleted,cover_url,owner_id
    projectService.insert(new Object[]{
            null, "title-xxl", "description", 1, null, 1, null, null, "", 1
    });
}

id created_at updated_at is_deleted 会使用默认的 DefaultColumnAutoFill 填充。

DefaultColumnAutoFill.java

public class DefaultColumnAutoFill implements ColumnAutoFill {

    @Override
    public Map<String, Object> insertFill() {
        Map<String, Object> fillMap = Maps.newHashMapWithExpectedSize(4);
        LocalDateTime now = LocalDateTime.now();
        fillMap.put("id", IdGenerator.getSequenceId());
        fillMap.put("created_at", now);
        fillMap.put("updated_at", now);
        fillMap.put("is_deleted", false);
        return fillMap;
    }

    @Override
    public Map<String, Object> updateFill() {
        Map<String, Object> fillMap = Maps.newHashMapWithExpectedSize(2);
        LocalDateTime now = LocalDateTime.now();
        fillMap.put("updated_at", now);
        return fillMap;
    }
}

也可以自已定义使 created_by updated_by 也会被自动填充

@Bean
public ColumnAutoFill fill() {
    return new ColumnAutoFill() {
        @Override
        public Map<String, Object> insertFill() {
            Map<String, Object> fill = new DefaultColumnAutoFill().insertFill();
            fill.put("created_by", 0);
            fill.put("updated_by", 0);
            return fill;
        }

        @Override
        public Map<String, Object> updateFill() {
            Map<String, Object> fill = new DefaultColumnAutoFill().updateFill();
            fill.put("updated_by", 0);
            return fill;
        }
    };
}
  • 添加数据(对象参数)
    public int insert(T t) 
@Test
public void testInsert() {
    Project project = new Project();
    project.setTitle("save T");
    project.setDescription("dddd");
    projectDAO.insert(project);
    System.out.println(project.getId());
    Assert.assertNotNull(project.getId());
}
  • 批量添加数据
public void insert(List<?> paramsList)

数组参数

@Test
public void testInsertAll() {
    List<Object[]> paramsList = Lists.newArrayList(
            new Object[]{
                    IDUtils.genItemId(), "title-b", "description", 1, LocalDateTime.now(), 1, LocalDateTime.now(), 0, "", 1
            },
            new Object[]{
                    IDUtils.genItemId(), "title-c", "description", 1, LocalDateTime.now(), 1, LocalDateTime.now(), 0, "", 1
            });
    projectService.insert(paramsList);
}

对象参数

@Test
public void testInsert() {
    Project project1 = new Project();
    project1.setTitle("save TT1");
    project1.setDescription("dddd1");
    project1.setCoverUrl("http://baidu.com");

    Project project2 = new Project();
    project2.setTitle("save TT2");
    project2.setDescription("dddd2");

    List<Project> list = Lists.newArrayList(project1, project2);

    projectDAO.insert(list);
}

删除数据delete

  • 根据ID删除数据
public void deleteById(Serializable id)
@Test
public void testDeleteById() {
    projectService.deleteById(11L);
}
  • 根据ID批量删除数据
public void deleteByIds(String ids)
@Test
public void testDeleteByIds() {
    projectService.deleteByIds("1632391637675732, 1632391637678836");
}

修改数据update

  • 根据ID更新数组参数
public int update(Object[] params, Serializable id)
@Test
public void testUpdate() {
    projectService.update(new Object[]{
        "title-update", "description", 1, LocalDateTime.now(), 1, LocalDateTime.now(), 0, "", 1
    }, 1341320525040701442L);
}
  • 根据ID更新数据,指定更新列
public int update(String updateColumnNames, Object[] params, Serializable id)
@Test
public void testUpdate2() {
    int count = projectService.update("title", new Object[]{
            "title-update",
    }, 1341320525040701442L);

    Assert.assertEquals(1, count);
}
  • 根据ID更新对象参数
public int update(T t)
@Test
public void testUpdate() {
    ProjectGroup2 project = new ProjectGroup2();

    project.setId(473905081847549952L);
    project.setTitle("yes =>");
    project.setGroupId(0L);
    project.setParentId(11L);
    project.setDeleted(true);
    Assert.assertEquals(1, projectGroup2DAO.update(project));
}

查询数据select

  • 根据ID查找数据
public Optional<T> selectById(Serializable id)
@Test
public void testSelectById() {
    Optional<Project> optional = projectService.selectById(1341320525040701442L);
    Project project = optional.get();
    Assert.assertEquals("title-update", project.getTitle());

    Optional<Project> optional2 = projectService.selectById(-12);
    Assert.assertEquals(false, optional2.isPresent());
}
  • 根据ID批量查找数据
public List<T> selectByIds(String ids)
public List<T> selectByIds(Collection<?> ids)
@Test
public void testSelectByIds() {
    List<Project> list = projectService.selectByIds("1341320525040701442,1341368810614910978");
    Assert.assertEquals(2, list.size());

    List<Project> list2 = projectService.selectByIds(Arrays.asList(1341320525040701442L));
    Assert.assertEquals(1, list2.size());
}
  • 根据条件查找数据1
public List<T> selectByParams(Map<String, Object> params)
@Test
public void testParams() {
    Map<String, Object> params = Maps.newHashMapWithExpectedSize(2);
    params.put("title", "haha");
    params.put("description", "world");
    List<Project> list = projectService.selectByParams(params);
    Assert.assertEquals(1, list.size());
}
  • 根据条件查找数据2
/**
 * name=23&age=15,13 => name=:name AND age IN(:age)
 *
 * @param queryString
 * @return
 */
public List<T> selectByParams(String queryString)
@Test
public void testParams2() {
    List<Project> list = projectService.selectByParams("title=haha&created_by=156629745675451,156629745675452");
    Assert.assertEquals(4, list.size());
}
  • 根据条件查找数据3,自定义条件SQL
public List<T> selectByParams(String queryString, String conditionSQL)
@Test
public void testParams3() {
    List<Project> list = projectService.selectByParams("title=haha&created_by=156629745675452,156629745675454", "title=:title OR created_by IN(:created_by)");
    Assert.assertEquals(6, list.size());
}
  • 获取所有数据
public List<T> selectAll()
@Test
public void testSelectAll() {
    List<Project> list = projectService.selectAll();
    System.out.println(list.size());
}

sharp-common集成Spring Web

sharp-common 集成Spring Web主要体现在以下3个方面

  • 通过注解 @RestControllerAdvice 封装异常异常 ApiExceptionHandler
  • 注入国际化的工具类 MessageUtils
  • 封装 Result 返回对象

集成

  • 添加包扫描,将 ApiExceptionHandlerMessageUtils纳入Spring上下文,@EnableResultWrapped 自动包裹 Result 对象。
    @Configuration
    @Import({ApiExceptionHandler.class, MessageUtils.class})
    @EnableResultWrapped
    public class MvcConfig implements WebMvcConfigurer {}
  • 国际化文件
# messages_en_US.properties
BEAN_VALIDATE_ERROR=Params validate error:{0}
MAX_TRY_LOGIN_ERROR=The account failed to log in {0} times, please wait {1} minutes and try again

# messages_zh_CN.properties
BEAN_VALIDATE_ERROR=参数验证错误:{0}
MAX_TRY_LOGIN_ERROR=该账号{0}次登录失败后,被锁定{1}分钟
  • 添加业务异常枚举
    @Getter
    @ToString
    public enum ExceptionCode {

        BEAN_VALIDATE_ERROR(30002, "BEAN_VALIDATE_ERROR"),
        PRICE_CRAWLER_ERROR(40004, "网站价格获取失败");

        private int code;

        private String msg;

        ExceptionCode(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        public ExceptionResult&lt;String&gt; result() {
            return new ExceptionResult&lt;&gt;(getCode(), getMsg());
        }
    }

BEAN_VALIDATE_ERROR 在国际化文件中进行了语言维护。

测试

@RestController
@RequestMapping("test")
public class TestController {

    @GetMapping("1")
    public Result test1() {
        return ResultUtils.success(MessageUtils.getMessage("MAX_TRY_LOGIN_ERROR", new Object[] {5, 20}));
    }

    @GetMapping("2")
    public Result test2() {
        int a = 1 / 0;
        return ResultUtils.success();
    }

    @GetMapping("3")
    public Result test3() {
        return ResultUtils.fail();
    }

    @GetMapping("4")
    public Result test4() {
        throw new BizException(ExceptionCode.FORMULA_ERROR.result());
    }

    @GetMapping("5")
    public Result test5() {
        throw new BizException(ExceptionCode.BEAN_VALIDATE_ERROR.result(), new Object[] {"姓名不能为空"});
    }

    @GetMapping("6")
    public int test5() {
        return 1;
    }

    @GetMapping("7")
    @UnWrapped
    public int test7() {
        return 7;
    }
}

注解 @UnWrapped 表示不需要被 Result 对象包裹。

sharp-sms使用指北

简介

sharp-sms 是基于阿里云的短信配置包依赖。

如何使用

添加 pom 依赖

<dependency>
    <groupId>com.rick.sms</groupId>
    <artifactId>sharp-sms</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

阿里云配置

application.yml

ali:
  access-key:
    id: LTAI4FkT323Aq4WU144WgZpwRA6D
    secret: U9eehrtFFsLt3SsP8E232TBhiyNh8Ghwvh

需要在阿里云的短信平台去获取

测试

@Autowired
private Sender sender;

@Test
public void testSend() {
    Map<String, String> params = new HashMap<>(3);
    params.put("name", "hello");
    params.put("value", "world");
    sender.send("18888888888", "XX公司", "SMS_202587654", params);
}

「XX公司」表示 签名,「SMS_202587654」表示 模版。 需要在阿里云的短信平台去配置。params参数就来自于 模版 中的变量。

sharp-common之JsonUtils

简介

Jackson是基于Java平台的一套数据处理工具,被称为”最好的Java Json解析器”。它可以使我们高效、简便的处理json字符串。

添加 pom 依赖

<dependency>
    <groupId>com.rick.common</groupId>
    <artifactId>sharp-common</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

对象转json字符串

public static String toJson(Object obj) throws IOException;
@Test
public void testToJson() throws IOException {
    Dept dept = new Dept();
    dept.setId(1L);
    dept.setName("Dev");
    dept.setParentId(2L);
    String json = JsonUtils.toJson(dept);
    System.out.println(json);
}

控制台输出

{"id":1,"name":"Dev","parentId":2}

json字符串转普通对象

public static <T> T toObject(String json, Class<T> clazz) throws IOException;

范型对象

@Test
public void testToPOJO() throws IOException {
    Dept dept = JsonUtils.toObject("{\"id\":1,\"name\":\"Dev\",\"parentId\":2}", Dept.class);
    Assert.assertEquals(1L, dept.getId().longValue());
}

Map对象

@Test
public void testToMap() throws IOException {
    Map dept = JsonUtils.toObject("{\"id\":1,\"name\":\"Dev\",\"parentId\":2}", Map.class);
    // dept.get("id") Integer类型
    Assert.assertEquals(1, dept.get("id"));
}

List对象

@Test
public void testToList() throws IOException {
    List list = JsonUtils.toObject("[{\"id\":1,\"name\":\"Dev\",\"parentId\":2}]", List.class);
    // dept.get("id") Integer类型
    Assert.assertEquals(1, ((Map)list.get(0)).get("id"));
}

json字符串转List

利用TypeReference,构造类型引用对象

@Test
public void testToListWithGenerics1() throws IOException {
    TypeReference<List<Dept>> typeRef = new TypeReference<List<Dept>>() {};
    List<Dept> list = JsonUtils.toObject("[{\"id\":1,\"name\":\"Dev\",\"parentId\":2}]", typeRef);
    Assert.assertEquals(1L, list.get(0).getId().longValue());
}

底层依赖利用JavaType实现

public static <T> List<T> toList(String json, Class<T> clazz) throws IOException;
@Test
public void testToListWithGenerics2() throws IOException {
    List<Dept> list = JsonUtils.toList("[{\"id\":1,\"name\":\"Dev\",\"parentId\":2}]", Dept.class);
    Assert.assertEquals(1L, list.get(0).getId().longValue());
}

json字符串转JsonNode

JsonNode后 ,操作对象比较转 Map List 对象更加的方便

public static JsonNode toJsonNode(String json) throws IOException;

list的Json字符串转JsonNode

@Test
public void testListStringToJsonNode() throws IOException {
    JsonNode jsonNode = JsonUtils.toJsonNode("[{\"id\":1,\"name\":\"Dev\",\"parentId\":2}]");
    Assert.assertEquals(1L, jsonNode.get(0).get("id").longValue());
}

对象的Json字符串转JsonNode

@Test
public void testObjectStringToJsonNode() throws IOException {
    JsonNode jsonNode = JsonUtils.toJsonNode("{\"id\":1,\"name\":\"Dev\",\"parentId\":2}");
    Assert.assertEquals(1L, jsonNode.get("id").longValue());
}

对象转JsonNode

@Test
public void testObjectToJsonNode() throws IOException {
    Dept dept = new Dept();
    dept.setId(1L);
    dept.setName("Dev");
    dept.setParentId(2L);
    JsonNode jsonNode = JsonUtils.toJsonNode(dept);
    Assert.assertEquals(1L, jsonNode.get("id").longValue());
}

Map转JsonNode

@Test
public void testMapToJsonNode() {
    String id = "1";
    Map<String, String> params = new HashMap<>();
    params.put("id", id);
    JsonNode jsonNode = JsonUtils.toJsonNode(params);
    Assert.assertEquals(1L, jsonNode.get("id").asLong());
}

sharp-meta操作指北

添加依赖

<dependency>
    <groupId>com.rick.meta</groupId>
    <artifactId>sharp-meta</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

创建脚本

create table sys_dict
(
type varchar(32) not null,
name varchar(32) not null,
label varchar(32) not null,
sort int null,
primary key (type, name)
)
charset=utf8mb4;

create table sys_property
(
name varchar(32) not null
primary key,
value varchar(255) not null
)
charset=utf8mb4;

INSERT INTO sys_dict (type, name, label, sort) VALUES ('sex', 'F', '女', 1);
INSERT INTO sys_dict (type, name, label, sort) VALUES ('sex', 'M', '男', 0);

INSERT INTO project_demo.sys_property (name, value) VALUES ('hello', 'world');

读取配置文件

application-dict.yml

dict:
  items:
    - type: user
      sql: "select username, name from sys_user order by id asc"
    - type: grade
      map: {g1: "一年级", g2: "二年级"}

创建测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class MetaTest {

    @Autowired
    private DictService dictService;

    @Autowired
    private PropertyService propertyService;

    @Test
    public void testList() {
        List<DictDO> sexList = dictService.getDictByType("sex");
        Assert.assertEquals(2, sexList.size());
    }

    @Test
    public void testGetOne() {
        DictDO dictDO = dictService.getDictByTypeAndName("sex", "F").get();
        Assert.assertEquals("女", dictDO.getLabel());
    }

    @Test
    public void testDictYml() {
        Assert.assertEquals(2, dictService.getDictByType("grade").size());
        Assert.assertEquals("一年级",dictService.getDictByTypeAndName("grade", "g1").get().getLabel());
        Assert.assertEquals("Rick",dictService.getDictByTypeAndName("user", "jkxyx205").get().getLabel());
        Assert.assertEquals("男",dictService.getDictByTypeAndName("sex", "M").get().getLabel());
    }

    @Test
    public void testGetProperty() {
        String property = propertyService.getProperty("hello");
        Assert.assertEquals("world", property);
    }

    @Test
    public void testSetProperty() {
        propertyService.setProperty("gg", "dd");
    }
}