# Example样例工程开发文档

本文档介绍基于LDP框架的Example样例工程开发流程，包含如何进行增删改查操作、如何使用REST远程调用已存在的业务接口、如何使用缓存等等。

## 一、数据接口

LDP框架支持两种操作方式，分别为Hibernate、JDBC。这两种操作方式都支持增删改查、列表查询、分页查询等。

### 1.1. Hibernate

#### 1.1.1 Hibernate接口方法

<details>
    <blockcode>
        <pre>
         /**
     * 新增
     *
     * @param o entity 对象
     */
    void insert(T o);
    /**
     * 批量新增
     *
     * @param list 列表数据
     */
    void insertList(List<T> list);
    /**
     * hibernate merge操作
     *
     * @param o entity 对象
     */
    void merge(T o);
    /**
     * merge批量操作
     *
     * @param list 列表
     */
    void merge(List<T> list);
    /**
     * 更新
     *
     * @param o entity 对象
     */
    void update(T o);
    /**
     * 动态更新，未设置的属性不做更新,默认以主键为查询条件
     *
     * @param o entity 对象
     */
    void dynamicUpdate(T o);
    /**
     * 批量动态更新
     *
     * @param list 列表
     */
    void dynamicUpdate(List<T> list);
    /**
     * 动态更新，设置属性为查询条件
     *
     * @param o
     * @param whereParam 自定义查询条件 ，map中key必须为entity存在字段
     */
    int dynamicUpdate(T o, Map<String, Object> whereParam);
    /**
     * 批量更新
     *
     * @param list 列表
     */
    void update(List<T> list);
    /**
     * 批量更新
     *
     * @param clazz        orm对象
     * @param updateFields 待更新字段集
     * @param whereParam   更新条件集
     *                     field
     * @return
     */
    int update(Class<T> clazz, Map<String, Object> updateFields, Map<String, Object> whereParam);
    /**
     * 删除
     *
     * @param o entity 对象
     */
    void delete(T o);
    /**
     * 批量删除
     *
     * @param clazz      需要修改的实体类
     * @param whereParam key：字段名 value：字段值，根据字段条件删除记录
     */
    int deleteList(Class<T> clazz, Map<String, Object> whereParam);
    /**
     * 删除
     *
     * @param clazz entity 类型
     * @param id    唯一标识
     */
    void delete(Class<T> clazz, K id);
    /**
     * 通过id查询
     *
     * @param clazz entity类型
     * @param id    唯一标识
     * @return entity 对象
     */
    T findById(Class<T> clazz, K id);
    /**
     * 计数
     *
     * @param clazz entity 类型
     * @return 数据条数
     */
    int count(Class<T> clazz);
    /**
     * 通过sql计数
     *
     * @param sql sql语句
     * @return 数据条数
     */
    int countBySQL(String sql);
    /**
     * 通过sql和参数计数
     *
     * @param sql      sql语句
     * @param paramMap 参数
     * @return 数据条数
     */
    int countBySQL(String sql, Map<String, Object> paramMap);
    /**
     * 查询所有数据
     *
     * @param clazz        entity类型
     * @param orderColumns 排序字段
     * @return 数据集
     */
    List<T> findALL(Class<T> clazz, OrderColumn... orderColumns);
    /**
     * hibernate 方式查询带参数
     *
     * @param clazz        entity类型
     * @param paramMap     参数
     * @param orderColumns 排序字段
     * @return 数据集
     */
    List<T> findByHql(Class<T> clazz, Map<String, Object> paramMap, OrderColumn... orderColumns);
    /**
     * hibernate 方式查询带参数
     *
     * @param hql        hql
     * @param paramMap     参数
     * @return 数据集
     */
    List<T> findByHql(String hql, Map<String, Object> paramMap);
    /**
     * hibernate 方式分页查询，带参数
     *
     * @param clazz        entity类型
     * @param paramMap     参数
     * @param pageIndex    当前页
     * @param pageSize     页面数据量
     * @param orderColumns 排序字段
     * @return 分页数据
     */
    Pagination findPageByHql(Class<T> clazz, Map<String, Object> paramMap, Object pageIndex, Object pageSize, OrderColumn... orderColumns);
     /**
     * hibernate 方式分页查询，带参数
     *
     * @param hql        hql
     * @param paramMap     参数
     * @param pageIndex    当前页
     * @param pageSize     页面数据量
     * @return 分页数据
     */
    Pagination findPageByHql(String hql, Map<String, Object> paramMap, Object pageIndex, Object pageSize);
    /**
     * hibernate 方式分页查询，带参数
     *
     * @param clazz        entity类型
     * @param pageIndex    当前页
     * @param pageSize     页面数据量
     * @param orderColumns 排序字段
     * @return 分页数据
     */
    Pagination findPageByHql(Class<T> clazz, Object pageIndex, Object pageSize, OrderColumn... orderColumns);
    /**
     * hibernate 方式分页查询，带参数
     *
     * @param hql        hql
     * @param pageIndex    当前页
     * @param pageSize     页面数据量
     * @return 分页数据
     */
    Pagination findPageByHql(String hql, Object pageIndex, Object pageSize);
    /**
     * 通过sql和参数查询entity数据集
     *
     * @param sql      sql语句
     * @param clazz    entity类型
     * @param paramMap 参数
     * @return 数据集
     */
    List<T> findEntityBySQL(String sql, Class<T> clazz, Map<String, Object> paramMap);
    /**
     * 通过sql查询entity数据集
     *
     * @param sql   sql语句
     * @param clazz entity类型
     * @return 数据集
     */
    List<T> findEntityBySQL(String sql, Class<T> clazz);
    /**
     * 通过sql和参数查询分页数据集
     *
     * @param sql       sql语句
     * @param clazz     entity类型
     * @param paramMap  参数
     * @param pageIndex 当前页
     * @param pageSize  页面数据量
     * @return 数据集
     */
    List<T> findEntityBySQL(String sql, Class<T> clazz, Map<String, Object> paramMap, Object pageIndex, Object pageSize);
    /**
     * 通过sql查询分页数据
     *
     * @param sql       sql语句
     * @param clazz     entity类型
     * @param pageIndex 当前页
     * @param pageSize  页面数据量
     * @return 数据集
     */
    List<T> findEntityBySQL(String sql, Class<T> clazz, Object pageIndex, Object pageSize);
    /**
     * 通过sql查询二维数组
     *
     * @param sql sql语句
     * @return 数据集
     */
    List<Object[]> findListArrayBySql(String sql);
    /**
     * 通过sql和参数查询二维数组
     *
     * @param sql      sql语句
     * @param paramMap 参数
     * @return 数据集
     */
    List<Object[]> findListArrayBySql(String sql, Map<String, Object> paramMap);
    /**
     * 通过sql和参数查询分页二维数组
     *
     * @param sql       sql语句
     * @param paramMap  参数
     * @param pageIndex 当前页
     * @param pageSize  数据量
     * @return 数据集
     */
    List<Object[]> findListArrayBySql(String sql, Map<String, Object> paramMap, Object pageIndex, Object pageSize);
    /**
     * 通过sql查询List<Map> 数据
     *
     * @param sql sql语句
     * @return 数据集
     */
    List<Map<String, Object>> findListMapBySql(String sql);
    /**
     * 通过sql查询List<Map> 数据
     *
     * @param sql      sql语句
     * @param paramMap 参数
     * @return 数据集
     */
    List<Map<String, Object>> findListMapBySql(String sql, Map<String, Object> paramMap);
    /**
     * 通过sql查询分页List<Map> 数据
     *
     * @param sql       sql语句
     * @param paramMap  参数
     * @param pageIndex 当前页
     * @param pageSize  数据量
     * @return 数据集
     */
    List<Map<String, Object>> findListMapBySql(String sql, Map<String, Object> paramMap, Object pageIndex, Object pageSize);
    /**
     * 通过sql和参数查询实体分页数据
     *
     * @param sql       sql语句
     * @param clazz     entity类型
     * @param paramMap  参数
     * @param pageIndex 当前页
     * @param pageSize  数据量
     * @return 分页数据
     */
    Pagination queryPageForListEntity(String sql, Class<T> clazz, Map<String, Object> paramMap, Object pageIndex, Object pageSize);
    /**
     * 通过sql和参数查询List<Map>分页数据
     *
     * @param sql       sql语句
     * @param paramMap  参数
     * @param pageIndex 当前页
     * @param pageSize  数据量
     * @return 分页数据
     */
    Pagination queryPageForListMap(String sql, Map<String, Object> paramMap, Object pageIndex, Object pageSize);
    /**
     * 通过sql查询实体分页数据
     *
     * @param sql       sql语句
     * @param clazz     entity类型
     * @param pageIndex 当前页
     * @param pageSize  数据量
     * @return 分页数据
     */
    Pagination queryPageForListEntity(String sql, Class<T> clazz, Object pageIndex, Object pageSize);
    /**
     * 通过sql和参数查询List<Map>分页数据
     *
     * @param sql       sql语句
     * @param pageIndex 当前页
     * @param pageSize  数据量
     * @return 分页数据
     */
    Pagination queryPageForListMap(String sql, Object pageIndex, Object pageSize);
    int executeSqlUpdate(String sql, Map<String, Object> params);
    /**
     * 事务级多query执行
     *
     * @param listQuery 事务集合
     * @return 影响行数
     */
    int executeTrans(LinkedList<TranscationQuery> listQuery);
    /**
     * hibernate 方式分页查询，带详细条件参数
     *
     * @param clazz        entity类型
     * @param conditions   条件参数
     * @param pageIndex    当前页
     * @param pageSize     页面数据量
     * @param orderColumns 排序字段
     * @return 分页数据
     */
    Pagination findPageByConditions(Class<T> clazz, LinkedList<Condition> conditions, Object pageIndex, Object pageSize, OrderColumn... orderColumns);
    /**
     * hibernate 方式查询，带详细条件参数
     *
     * @param clazz        entity类型
     * @param conditions   条件参数
     * @param orderColumns 排序字段
     * @return 数据集
     */
    List<T> findByConditions(Class<T> clazz,LinkedList<Condition> conditions, OrderColumn... orderColumns);
    	</pre>
    </blockcode>
</details>


#### 1.1.2 Hibernate调用示例

参照com.sinra.ldp.example.service.impl.ExampleServiceImpl.java，这里需要注意的是 **@AutoService** 注解，这个注解主要是在新增和更新时，对于实体类中配置了@AutoComputed字段根据规则进行自动填充。例如

```java
    @Column(name = "create_time")
    @AutoComputed(command = ComputedCommand.DATETIME)
    private Date createTime;
```

这里会以当前时间填充到createTime字段中。command目前支持6种自动填充，分别为：

AUTO：根据字段名进行填充。

MD5：将字段值进行一次md5加密。

DATETIME：当前时间。

USERID：当前登录用户。

UUID：生成32位随机字符串。

PINYIN：将ref字段的拼音填充到此字段中。

```java
 // AutoService注解在新增时会对实体类中配置了@AutoComputed字段根据规则进行填充
    @Override
    @AutoService
    public void add(ExampleUserInfo exampleUserInfo) {
        genericDaoService.insert(exampleUserInfo);
    }

    @Override
    @AutoService
    public void add(List<ExampleUserInfo> list) {
        genericDaoService.insertList(list);
    }

    @Override
    public ExampleUserInfo find(String s) {
        return (ExampleUserInfo) genericDaoService.findById(ExampleUserInfo.class, s);
    }

    // AutoService注解在更新时会对实体类中updateId、updateTime、sortName进行自动填充
    @Override
    @AutoService(init = false)
    public void update(ExampleUserInfo exampleUserInfo) {
        genericDaoService.update(exampleUserInfo);
    }

    @Override
    @AutoService(init = false)
    public void update(List<ExampleUserInfo> list) {
        genericDaoService.update(list);
    }

	@Override
    public void update(Class<ExampleUserInfo> aClass, Map<String, Object> updateFileds, Map<String, Object> whereParam) {
        genericDaoService.update(aClass, updateFileds, whereParam);
    }

    @Override
    public void delete(ExampleUserInfo exampleUserInfo) {
        genericDaoService.delete(exampleUserInfo);
    }

    @Override
    public void delete(List<ExampleUserInfo> list) {
        String[] idList = new String[list.size()];
        Map<String, Object> param = new HashMap<>(1);
        param.put("id", idList);
        genericDaoService.deleteList(ExampleUserInfo.class, param);
    }

    @Override
    public List<ExampleUserInfo> findList(Map<String, Object> map) {
        return genericDaoService.findByHql(ExampleUserInfo.class, map);
    }

    @Override
    public Pagination<ExampleUserInfo> findPage(Pagination page, Map<String, Object> map) {
        return genericDaoService.findPageByHql(ExampleUserInfo.class, map, page.getPageIndex(), page.getPageSize());
    }
```

**PS：带有sql参数的方法使用请参照[JDBC调用示例](#JDBC调用示例)**

### 1.2. JDBC

#### 1.2.1 JDBC接口方法

<details>
    <blockcode>
        <pre>
         /**
     * 分页查询，带参数，返回分页对象，data类型为list:entity
     * 进行分页查询
     *
     * @param sql        sql语句
     * @param entityType entity类型
     * @param paramMap   参数
     * @param pageIndex  当前页码
     * @param pageSize   数据量
     * @return 分页数据
     */
    public <T> Pagination queryPageForListEntity(String sql, Class<T> entityType, Map<String, Object> paramMap, int pageIndex, int pageSize);
    /**
     * 分页查询，返回分页对象，data类型为list:entity
     * 进行分页查询
     *
     * @param sql        sql语句
     * @param entityType entity类型
     * @param pageIndex  当前页码
     * @param pageSize   数据量
     * @return 分页数据
     */
    public <T> Pagination queryPageForListEntity(String sql, Class<T> entityType, int pageIndex, int pageSize);
    /**
     * 分页查询，带参数，返回分页对象，data类型为list:map
     *
     * @param sql       sql语句
     * @param paramMap  参数
     * @param pageIndex 当前页
     * @param size      数据量
     * @return 分页数据
     */
    public <T> Pagination queryPageForListMap(String sql, Map<String, Object> paramMap, int pageIndex, int size);
    /**
     * 分页查询，带参数，返回分页对象，data类型为list:map
     *
     * @param sql       sql语句
     * @param pageIndex 当前页
     * @param size      数据量
     * @return 分页数据
     */
    public <T> Pagination queryPageForListMap(String sql, int pageIndex, int size);
    /**
     * 查询不带参数，返回list:map
     *
     * @param sql sql语句
     * @return 数据集
     */
    public List<Map<String, Object>> queryForList(String sql);
    /**
     * 查询带参数，返回list:map
     *
     * @param sql      sql语句
     * @param paramMap 参数
     * @return 数据集
     */
    public List<Map<String, Object>> queryForList(String sql, Map<String, Object> paramMap);
    /**
     * 查询不带参数，返回list:entity
     *
     * @param sql        sql语句
     * @param entityType entity类型
     * @return 数据集
     */
    public <T> List<T> queryForList(String sql, Class<T> entityType);
    /**
     * 查询带参数，返回list:entity
     *
     * @param sql        sql语句
     * @param entityType bean类型
     * @param paramMap   参数map
     * @return 数据集
     */
    public <T> List<T> queryForList(String sql, Class<T> entityType, Map<String, Object> paramMap);
    /**
     * 执行sql
     *
     * @param sql sql语句
     * @return 影响行数
     */
    public int excute(String sql);
    /**
     * 执行sql 带参数
     *
     * @param sql      sql语句
     * @param paramMap 参数
     * @return 影响行数
     */
    public int excute(String sql, Map<String, Object> paramMap)
    /**
     * 批量sql执行，不带参数
     *
     * @param sql sql语句
     * @return 影响行数数组
     */
    public int[] batchExcute(String... sql);
    /**
     * 执行同一sql，批量参数
     *
     * @param sql          sql语句
     * @param listParamMap 参数
     * @return 影响行数数组
     */
    public int[] execute(String sql, List<Map<String, Object>> listParamMap);
    /**
     * 事务级多query执行
     *
     * @param listQuery 事务集合
     * @return 影响行数
     */
    int executeTrans(LinkedList<TranscationQuery> listQuery);
        </pre>
    </blockcode>
</details>

#### 1.2.2 JDBC调用示例

在example-biz模块，src/main/resources/query目录下新建xxxxservice-query.xml文件【建议拷贝**exampleservice-query.xml**文件】。

1、修改**queryspace**标签中的**ref**属性，ref属性表示文件中的sql语句会在哪里使用，例如下面表示sql语句会在**com.sinra.ldp.example.service.impl.ExampleServiceImpl**中使用到

```xml
<?xml version="1.0" encoding="UTF-8"?>
<queryspace
        xmlns="http://www.w3schools.com"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="query-template.xsd"
        ref="com.sinra.ldp.example.service.impl.ExampleServiceImpl">
    
    <query id="examplelist" author="machao" remark="列表数据">
        <!--  使用【:参数名】预留参数，在#间，表示可选，如果不传，就会忽略此参数, 建议在参数和#间添加空格	-->
        <!--  根据数据库类型自动读取对应标签中的sql语句，如果不存在，默认读取sql标签下的语句  -->
        <sql>
            <![CDATA[
				select * from ldp_mcs_user_info where # user_type=:userType #
			  ]]>
        </sql>
        <oracle>
            <![CDATA[
			     select * from ldp_mcs_user_info where # user_type=:userType #
			  ]]>
        </oracle>
        <mysql>
            <![CDATA[
				select * from ldp_mcs_user_info where # user_type=:userType #
			  ]]>
        </mysql>
        <sqlserver>
            <![CDATA[
				select * from ldp_mcs_user_info where # user_type=:userType #
			  ]]>
        </sqlserver>
    </query>
</queryspace>

```

2、在对应的的实现类中使用**@QueryBind**注解，这个注解会将指定sql自动注入到方法的**第一个参数**中。

```java
/**
* jdbc查询， QueryBind所对应的sql语句在resource/query/exampleservice中
* 调用时 getUserListByJDBC(StringUtils.EMPTY); 注解会将sql语句自动注入到参数中
*
* @param sql
* @return
*/
@QueryBind("examplelist")
@Override
public List<ExampleUserInfo> getUserListByJDBC(String sql, Map<String, Object> param) {
    List<ExampleUserInfo> exampleUserInfos = jdbcDaoService.queryForList(sql, ExampleUserInfo.class, param);
    return exampleUserInfos;
}
```

3、在其它地方调用上面定义的方法时，第一个参数直接传入**StringUtils.EMPTY**。

```java
Map<String, Object> param = new HashMap<>(1);
param.put("userType", 0);
List<ExampleUserInfo> exampleUserInfos = exampleService.getUserListByJDBC(StringUtils.EMPTY, param);
```

## 二、远程调用其它模块接口

对于已存在的其它服务接口，需要通过Rest 请求来调用，这里推荐使用**RestTemplate**，根据 http://api.dev.shxrtech.com/ 的API文档，使用**NACOS**自动解析服务名。例如，调用**mcs-service**模块的[**/user/get/page**](  http://api.dev.shxrtech.com/project/25/interface/api/414 )接口，拼接完整的请求地址为http://mcs-service/user/get/page ，根据文档，必填参数为pageIndex，pageSize，代码如下：

```java
/**
* rest查询，使用服务名+接口名： 这里使用mcs-service服务，调用用户获取列表接口
*
* @return
*/
@Override
public Pagination getUserListByRest() {
    HttpHeaders headers = new HttpHeaders();
    headers.add("Accept", MediaType.APPLICATION_JSON.toString());
    HttpEntity<String> entity = new HttpEntity(headers);
    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://mcs-service/user/get/page")
        .queryParam("pageIndex", 1)
        .queryParam("pageSize", 5);
    ResponseEntity<RestResult<Pagination<Map<String, Object>>>> response = restTemplate.exchange(builder.toUriString(),
                                                                                                 HttpMethod.GET,
                                                                                                 entity,
                                                                                                 new ParameterizedTypeReference<RestResult<Pagination<Map<String, Object>>>>() {
                                                                                                 });
    return response.getBody().getData();
}
```

也可以直接使用Feign来做Rest请求，首先定义FeignClient，将服务名填写到注解中。通过注解描述出需要请求的接口地址、请求方式、参数以及返回值，省略掉发送请求和解析结果的实现。

```java
/**
 * Feign请求mcs-service样例代码
 * <p>
 * 需要注解 @FeignClient并在注解中填上服务名
 *
 * @author machao
 */
@FeignClient("mcs-service")
public interface ExampleFeignService {


    /**
     * 通过Feign获取用户分页数据
     * <p>
     * 用注解写出请求地址/方法，以及参数和返回值
     *
     * @param index 页码
     * @param size  每页数据数量
     * @return 用户分页数据
     */
    @RequestMapping(value = "/user/get/page", method = RequestMethod.GET)
    RestResult<Pagination<LdpMcsUserInfo>> getUserPageByFeign(@RequestParam("pageIndex") int index, @RequestParam("pageSize") int size);
}
```

将服务注入到Rest层中，并调用接口拿到返回值

```java
    @Autowired
    ExampleFeignService exampleFeignService;

	/**
     * rest获取用户分页数据
     *
     * @return
     */
    @GetMapping("/rest/feign/page")
    public RestResult getPageByFeign() {
        //直接调用在FeignClient定义的接口
        return exampleFeignService.getUserPageByFeign(0, 10);
    }
```



## 三、缓存使用

在LDP中缓存分为两种，分别为**SessionCache**、**ApplicationCache**。在使用**SessionCache**之前，需要先通过**UAA**的登录，或者在请求头中携带有效的**X-Ldp-Token**【**PS：当前没有会话或者会话过期后，SessionCache就不可用**】，而**ApplicationCache**只要不手动清空，缓存会一直存在。

| 类型             | 生命周期         | 缓存过期时间                 |
| ---------------- | ---------------- | ---------------------------- |
| SessionCache     | 跟随会话         | 会话过期                     |
| ApplicationCache | 跟随应用生命周期 | 永不过期（除非手动删除缓存） |

缓存使用也有2中方式，分别为注解方式、手动调用put与get，使用注解更简单，但是使用put和get更灵活，请根据使用场景判断使用适合的方案。

### 3.1. 注解方式

缓存注解目前支持两种 **@SessionCacheable** 和 **@ApplicationCacheable** ，将注解添加到Rest层方法上，会自动将方法结果缓存下来，之后再次调用此接口，会直接从缓存中获取。例如（参考example-biz模块中的com.sinra.ldp.example.rest.ExampleRest.java）：

```java
    /**
     * jdbc 获取用户list
     *
     * @param paramMap
     * @return
     * @throws Exception
     */
    @GetMapping("/jdbc/list")
    @SessionCacheable
    public RestResult jdbcList(@RequestParamMap(typeCovertMapping = ExampleUserInfo.class) Map<String, Object> paramMap) throws Exception {
        List<ExampleUserInfo> userInfoList = exampleService.getUserListByJDBC(StringUtils.EMPTY, paramMap);
        return new RestResult(ResultMsg.SUCCESS, userInfoList);
    }

    /**
     * rest获取用户分页数据
     *
     * @return
     */
    @GetMapping("/rest/page")
    @ApplicationCacheable
    public RestResult restList() {
        return new RestResult(ResultMsg.SUCCESS, exampleService.getUserListByRest());
    }
```

### 3.2. 手动put、get

先在需要使用的地方注入**ApplicationCache**或者**SessionCache**，然后根据业务调用对应的get、put方法。参考example-biz模块中的com.sinra.ldp.example.service.impl.ExampleServiceImpl.java：

```java

    @Autowired
    ApplicationCache applicationCache;

	/**
     * 使用ApplicationCache做列表数据缓存
     *
     * @return 列表数据
     */
    @Override
    public List<ExampleUserInfo> findListByApplicationCache() {
        //缓存key
        String cacheKey = this.getClass().getName() + "findListByApplicationCache";
        //如果缓存有这个数据，则从缓存中获取
        if (applicationCache.get(cacheKey) != null) {
            return applicationCache.get(cacheKey, List.class);
        }
        //如果没有则从DB获取，并放到缓存中
        List<ExampleUserInfo> list = genericDaoService.findByHql(ExampleUserInfo.class, new HashMap<>(1));
        applicationCache.put(cacheKey, list);
        return list;
    }
```

### 3.3. 获取当前登录用户信息

通过SessionCache，可以获取当前登录用户信息。先注入 **SessionCache** ，然后调用 **existUserToken()** 判断是否存在token，如果存在，就可以获取当前登录用户信息，参考example-biz模块中的com.sinra.ldp.example.service.impl.ExampleServiceImpl.java：

```java
	@Autowired
    SessionCache sessionCache;

	/**
     * 从Session缓存中获取当前登录用户，如果没有登录用户则返回一个空用户
     *
     * @return 当前用户
     */
    @Override
    public LdpMcsUserInfo getCurrentUser() {
        if (sessionCache.existUserToken()) {
            return sessionCache.getCurrentUser();
        }
        return new LdpMcsUserInfo();
    }
```

### 3.4. 刷新缓存

**SessionCache** 可以通过重新登录的方式刷新缓存，也可以通过重新调用put方法刷新，**ApplicationCache** 是不会过期的，需要调用put方法刷新缓存。 **ApplicationCache** 以及 **SessioinCache** 都提供了 **getCacheKey** 方法来获取缓存key，在想要刷新缓存的地方直接获取到缓存key，然后put最新数据到缓存中，下面是一个案例：

```java
@Autowired
ApplicationCache applicationCache;

/**
* rest获取用户分页数据
*
* @return
*/
@GetMapping("/rest/page")
//这里使用注解方式
@ApplicationCacheable
public RestResult getListByRest() {
    return new RestResult(ResultMsg.SUCCESS, exampleService.getUserListByRest());
}



/**
* 刷新rest获取用户分页参数结果
*
* @return
*/
@GetMapping("/rest/page/refresh")
public RestResult refreshGetListByRest() {
    Pagination pagination = exampleService.getUserListByRest();
    // 获取到缓存key
    String cacheKey = applicationCache.getCacheKey(ExampleRest.class, "getListByRest");
    // 重新存入数据到缓存中
    applicationCache.put(cacheKey, pagination);
    return new RestResult(ResultMsg.SUCCESS, pagination);
}

```
## 四、编码规则使用
LDP框架支持自动生成编码，在使用编码规则时，需预先在系统中配置一个编码规则。各业务模块在使用的时候，
根据编码规则的Key，进行生成最新的一个编码。生成编码后，将生成的编码set到业务实体当中的编码字段中，保存到数据库持久化即可。

**依赖common-codingrule**

```xml
	<dependency>
            <groupId>com.sinra.ldp</groupId>
            <artifactId>common-codingrule</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
```
```java
 @Autowired
 private CodingruleUtils codingruleUtils;


    /**
     * 根据预先设置好的编码规则，进行生成编码。
     * codingruleUtils.getNumber(key)，业务模块代码中，可直接进行注入使用，依赖common-codingrule包
     * @param key 编码规则的Key
     * @return
     *
     */
    @GetMapping("/generateNumber")
    public RestResult generateNumber(String key){

        String number = codingruleUtils.getNumber(key);
        /**
         * 获取到number后，set到业务实体中即可
         * 业务代码.......
         *
         */
        return new RestResult(ResultMsg.SUCCESS,number);
    }
```

## 五、接口调用日志使用介绍
在实际系统业务应用当中，少不了的是系统与系统之间的数据传输。一般情况下是利用系统之间开放接口进行调用。
记录接口调用日志，也成为了系统必不可少的一部分。方便开发人员排查问题。
在LDP框架当中，开放对外的接口或调用了外部系统的接口方法内，需进行记录接口调用日志。
依赖**common-log**模块

```xml
<dependency>
      <groupId>com.sinra.ldp</groupId>
      <artifactId>common-log</artifactId>
      <version>1.0-SNAPSHOT</version>
</dependency>
        
```


```java
@Autowired
private InterfaceLogBaseService interfaceLogBaseService;
```
```java
InterfaceAddLogVo interfaceAddLogVo = new InterfaceAddLogVo();
        String url = "http://localhost:8800/interface/test";
        String params = "&name=lisw&number=001";
        String result= sendPost(url,params);
        interfaceAddLogVo.setIsOut(true)
                .setName("Example工程测试接口")
                .setParams(params)
                .setResult(result)
                .setUrl(url)
                .setReceiver("信睿LDP框架接收")
                .setSender("信睿LDP框架发送");
        interfaceLogBaseService.saveLog(interfaceAddLogVo,request);

```
**注：**
isOut字段标识接口类型，false：外部系统调用本系统，true:本系统调用外部系统，当isOut字段为false时，url字段可不进行设值，saveLog方法会自动通过request进行获取。反之，isOut字段为true时，url字段值需设置为外部系统的接口地址，saveLog方法的request参数，传Null即可。

## 六、数据字典的引用
各业务模块实体中，如果有需要用到数据字典的字段，则将数据字典的主键ID存入到业务实体当中即可。在业务实体当中利用Hibernate关联即可。

```java
	/**
     * 人员性别
     */
    @ManyToOne(fetch = FetchType.EAGER,cascade = {CascadeType.REFRESH})
    @JoinColumn(name = "sex")
    private DictInfo2 sex;//数据类别
   
```

## 七、业务异常处理

LDP业务异常类是`BizException`，最简单的使用方式就是，传入code和message，并抛出BizException

```java
try{
    ......
    ......
} catch{
    throw new BizException(500,"业务异常")
}

//或者

if(condition) {
    throw new BizException(500,"业务异常")
}
```

有时候我们需要考虑国际化，需要在startup模块下的resources目录中国际化文件中写上对应的code和message，当浏览器为英文时，使用en_US文件中的code和message，否则使用zh_CN文件，如果两个文件都没写，则默认使用**messages.properties**中的code以及message。

![bizException](../imgs/biz-exception.png)

写好code和message后，注入MessageSourceHandler，并调用newBizException方法，传入去掉code和message的错误编码。以下是样例，如果删除的id值为“error-1”则抛出业务异常（参考脚手架工程ExampleRest类）。

```java
	@Autowired
    MessageSourceHandler messageSourceHandler;

	/**
     * 删除用户
     *
     * @param id
     * @return
     */
    @PostMapping("/del/{id}")
    public RestResult deleteUser(@PathVariable("id") String id) {
        if ("error-1".equals(id)) {
            throw messageSourceHandler.newBizException("example.biz.demo.del.error");
        }
        ExampleUserInfo userInfo = new ExampleUserInfo(id);
        exampleService.delete(userInfo);
        return new RestResult(ResultMsg.SUCCESS, "");
    }
```



