尚医通 项目 学习总结(1)

  1. 如何自定义异常处理?
  2. 日志级别,如何将日志输出到本地硬盘文件?
  3. 前端 管理页面如何实现删除,批量删除?
    批量删除时如何取多个值?

医院设置swagger接口:http://localhost:8201/swagger-ui.html

注意点
在这里插入图片描述
data: searchObj 表示对象会以 json 传递
不用json传递 params
在这里插入图片描述

遇到错误

1 npm run dev 启动时报错

Found bindings for the following environments: - Windows 64-bit with Node.js

需要重装node-sass包
npm rebuild node-sass

1 搭建后端环境

1.1 准备初始环境

springboot 2.2.1.RELEASE

创建一个springboot工程
在这里插入图片描述
在这里插入图片描述
父工程 放版本依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cn</groupId>
    <artifactId>yyghm_parent</artifactId>
    <packaging>pom</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>yyghm_parent</name>
    <description>Demo project for Spring Boot</description>
    <!--依赖版本-->
    <properties>
        <java.version>1.8</java.version>
        <cloud.version>Hoxton.RELEASE</cloud.version>
        <alibaba.version>2.2.0.RELEASE</alibaba.version>
        <mybatis-plus.version>3.3.1</mybatis-plus.version>
        <mysql.version>5.1.46</mysql.version>
        <swagger.version>2.7.0</swagger.version>
        <jwt.version>0.7.0</jwt.version>
        <fastjson.version>1.2.29</fastjson.version>
        <httpclient.version>4.5.1</httpclient.version>
        <easyexcel.version>2.2.0-beta2</easyexcel.version>
        <aliyun.version>4.1.1</aliyun.version>
        <oss.version>3.9.1</oss.version>
        <jodatime.version>2.10.1</jodatime.version>
    </properties>

    <!--配置dependencyManagement锁定依赖的版本-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--mybatis-plus 持久层-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>

            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>

            <!--swagger-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>${swagger.version}</version>
            </dependency>
            <!--swagger ui-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>${swagger.version}</version>
            </dependency>

            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>${jwt.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>${httpclient.version}</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>easyexcel</artifactId>
                <version>${easyexcel.version}</version>
            </dependency>

            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-sdk-core</artifactId>
                <version>${aliyun.version}</version>
            </dependency>

            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>${oss.version}</version>
            </dependency>

            <!--日期时间工具-->
            <dependency>
                <groupId>joda-time</groupId>
                <artifactId>joda-time</artifactId>
                <version>${jodatime.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>


</project>

2 搭建common模块 及common模块下的两个子模块common-utilservice-util
在这里插入图片描述
common 配置文件中添加依赖

	<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>provided </scope>
        </dependency>

        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <scope>provided </scope>
        </dependency>

        <!--lombok用来简化实体类:需要安装lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>
    </dependencies>

common-util

	<dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
        </dependency>

        <!-- 日期工具栏依赖 -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>
    </dependencies>

模块model 实体类 VO类

在这里插入图片描述

1.2 提交git仓库

https://gitee.com/shixumin/yyghm_parent.git

选中仓库位置
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1.3 整合swagger 接口

  1. 先引入swagger依赖
  2. 添加配置类
  3. 在启动类添加扫描规则
  4. 访问 localhost:8201/swagger-ui.html

在这里插入图片描述

1.4 统一返回结果定义

在这里插入图片描述

1.5 医院设置CURD 接口开发

1.5.1 查看医院设置表所有信息

    //1. 查询医院设置表所有信息

    @ApiOperation(value = "获取所有医院设置信息")
    @GetMapping("findAll")
    public Result findAllHospitalSet(){
        //调用service的方法
        List<HospitalSet> list = hospitalSetService.list();
//        Result<List<HospitalSet>> ok = Result.ok(list);
        return Result.ok(list);
    }

1.5.2 逻辑删除医院设置

    //2. 逻辑删除医院设置
    @ApiOperation(value = "逻辑删除医院设置信息")
    @DeleteMapping("{id}")
    public Result removeHospSer(@PathVariable long id){
        boolean flag = hospitalSetService.removeById(id);
        if (flag){
            return Result.ok();
        }else {
            return Result.fail();
        }
    }

1.5.3 医院设置信息-分页条件查询

注意:@RequestBody 的使用 :接收前端传递给后端的 json

在这里插入图片描述

//3.条件查询分页
//    @RequestBody(required = false)//json形式传递,required=false可以为空    post提交才能得到requestbody传来的值
    @PostMapping("findPage/{current}/{limit}")
    public Result findPageHospSet(@PathVariable long current,
                                  @PathVariable long limit,
                                  @RequestBody(required = false) HospitalSetQueryVo hospitalSetQueryVo){
        //创建page对象,传递当前页,每页记录数
        Page<HospitalSet> page = new Page<>(current, limit);

        //构建条件
        QueryWrapper<HospitalSet> wrapper = new QueryWrapper<>();
        //先对条件值进行判断,有的话设置
        String hosname = hospitalSetQueryVo.getHosname();//医院名称
        String hoscode = hospitalSetQueryVo.getHoscode();//医院编号
        if (!StringUtils.isEmpty(hosname)){
            wrapper.like("hosname", hospitalSetQueryVo.getHosname());
        }
        if (!StringUtils.isEmpty(hoscode)){
            wrapper.eq("hoscode", hospitalSetQueryVo.getHoscode());
        }

        //调用方法实现分页查询
        Page<HospitalSet> hospitalSetPage = hospitalSetService.page(page, wrapper);

        return Result.ok(hospitalSetPage);
    }

在这里插入图片描述

1.5.4 添加

    //4.添加医院设置
    @PostMapping("saveHospitalSet")
    public Result saveHospitalSet(@RequestBody HospitalSet hospitalSet){
        //设置状态 1 使用   ; 2 不能使用
        hospitalSet.setStatus(1);
        //签名密钥  与医院接口对接时使用
        Random random = new Random();
                //根据当前时间和一个随机数
        hospitalSet.setSignKey(MD5.encrypt(System.currentTimeMillis()+""+random.nextInt(1000)));
        //调用service
        boolean save = hospitalSetService.save(hospitalSet);
        if (save){
            return Result.ok();
        }else {
            return Result.fail();
        }
    }

添加测试数据

{
  "apiUrl": "http://localhost:8999",
  "contactsName": "张三",
  "contactsPhone": "1291012",
  "hoscode": "1000_01",
  "hosname": "北京人民医院",
  "isDeleted": 0
}

在这里插入图片描述
状态和时间有设置默认值
在这里插入图片描述

1.5.5 根据id获取医院设置

    //5.根据id获取医院设置
    @ApiOperation(value = "根据id获取医院设置")
    @GetMapping("getHospSet/{id}")
    public Result getHospSet(@PathVariable Long id){
        HospitalSet hospitalSet = hospitalSetService.getById(id);
        return Result.ok(hospitalSet);
    }

1.5.6 修改医院设置

    //6.修改医院设置
    @ApiOperation(value = "修改医院设置")
    @PostMapping("updateHospitalSet")
    public Result updateHospitalSet(@RequestBody HospitalSet hospitalSet){
        boolean flag = hospitalSetService.updateById(hospitalSet);
        if (flag){
            return Result.ok();
        }else {
            return Result.fail();
        }
    }

1.5.7 批量删除医院设置

    //7.批量删除医院设置
    @ApiOperation(value = "批量删除医院设置")
    @DeleteMapping("batchRemove")
    public Result batchRemoveHospitalSet(@RequestBody List<Long> idList){
        hospitalSetService.removeByIds(idList);
        return Result.ok();
    }

1.5.8 医院设置 锁定与解锁

    //8 医院设置 锁定与解锁
    @PutMapping("lockHospitalSet/{id}/{status}")
    public Result lockHospitalSet(@PathVariable Long id,
                                  @PathVariable Integer status){
        //根据id查询医院设置信息
        HospitalSet hospitalSet = hospitalSetService.getById(id);
        //设置状态
        hospitalSet.setStatus(status);
        //调用方法
        hospitalSetService.updateById(hospitalSet);
        return Result.ok();
    }

1.5 全局异常处理

异常时出现统一的提示

测试异常返回通知
在这里插入图片描述

在这里插入图片描述
添加全局异常处理类 GlobalExceptionHandler

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)   //指定什么异常
    @ResponseBody       //使结果以json形式输出
    public Result error(Exception e){
        e.printStackTrace();
        return Result.fail();
    }
}

返回统一的提示
在这里插入图片描述

自定义异常

自定义异常需要手动 抛出

/**
 * 自定义全局异常类
 *
 * @author qy
 */
@Data
@ApiModel(value = "自定义全局异常类")
public class YyghException extends RuntimeException {

    @ApiModelProperty(value = "异常状态码")
    private Integer code;

    /**
     * 通过状态码和错误消息创建异常对象
     * @param message
     * @param code
     */
    public YyghException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    /**
     * 接收枚举类型对象
     * @param resultCodeEnum
     */
    public YyghException(ResultCodeEnum resultCodeEnum) {
        super(resultCodeEnum.getMessage());
        this.code = resultCodeEnum.getCode();
    }

    @Override
    public String toString() {
        return "YyghException{" +
                "code=" + code +
                ", message=" + this.getMessage() +
                '}';
    }
}

在这里插入图片描述
后端控制台
在这里插入图片描述
在这里插入图片描述

1.7 日志

  1. 日志等级
    OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL

  2. 设置日志级别
    在相应的项目配置文件中加入
    logging.level.root=DEBUG

  3. 如何把日志输出到硬盘文件
    spring boot内部使用Logback作为日志实现的框架。
    Logback和log4j非常相似
    在resource下创建配置文件 logback-spring.xml
    在这里插入图片描述

2 搭建前端环境

将压缩文件解压到工作区
在这里插入图片描述

打开终端

# 安装依赖
npm install
# 启动。执行后,浏览器自动弹出并访问http://localhost:9527/
npm run dev

在这里插入图片描述
使用该插件的话下载 ESlint

在这里插入图片描述

先使其成功登录
在这里插入图片描述
先把登录数据改为固定值

管理平台 前端部分开发步骤

在这里插入图片描述

1. 路由的添加

src/router/index.js
在这里插入图片描述

2. 页面跳转路径

创建跳转页面,设置跳转路径
在这里插入图片描述

3. 接口路径定义

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

跨域问题

前端项目端口号9528,后端接口端口号8201 ,端口号不同 ,不允许访问

在这里插入图片描述
在controller中加入 @CrossOrigin注解

4

将前端成功状态码20000 改为200
在这里插入图片描述
list.vue

<template>
    <div class="app-container">
        医院设置列表
    </div>
</template>

<script>
import hospset from '@/api/hospset'

export default{
    //定义变量和初始值
    data(){
        return{
            current:1,      //当前页
            limit:3,        //每页显示记录数
            searchObj:{},   //条件封装对象
            list:[],         //每页数据集合
            total:0          //总记录数
        }
    },
    created(){              //在页面渲染之前进行
                            //一般调用methods定义方法,得到数据
        this.getList()      //只能调用当前vue方法
    },
    methods:{               //定义方法,进行请求接口调用
        //医院设置列表
        getList(){
            hospset.getHospSetList(this.current,this.limit,this.searchObj)
                .then(response=>{ //请求成果response是接口返回数据
                    //返回集合赋值list
                    this.list=response.data.records
                    //总记录数
                    this.total=response.data.total
                    // console.log(response)
                })  //请求成功
                .catch(error=>{
                    console.log(error)
                })

    }
    
    }
}
</script>

注意:如何返回集合赋值list
在这里插入图片描述

利用elment-ui前端页面显示

<template>
    <div class="app-container">
        医院设置列表

        <!-- banner列表 -->
        <el-table :data="list" stripe style="width: 100%">

            <el-table-column type="index" width="50" lable="序号"/>
            <el-table-column prop="hosname" label="医院名称"/>
            <el-table-column prop="hoscode" label="医院编号"/>
            <el-table-column prop="apiUrl" label="api基础路径"width="200"/>
            <el-table-column prop="contactsName" label="联系人姓名"/>
            <el-table-column prop="contactsPhone" label="联系人手机"/>

            <!-- ===表示值和类型都相同 -->
            <el-table-column label="状态" width="80">
            <template slot-scope="scope">
                    {{ scope.row.status === 1 ? '可用' : '不可用' }}
            </template>
            </el-table-column>
        </el-table>

    </div>
</template>

在这里插入图片描述

前端页面实现分页

添加当前页参数
在这里插入图片描述
添加分页插件

        <!-- 分页 -->
        <el-pagination
        :current-page="current"
        :page-size="limit"
        :total="total"
        style="padding: 30px 0; text-align: center;"
        layout="total, prev, pager, next, jumper"
        @current-change="getList" />

在这里插入图片描述

前端页面实现模糊查询

 		医院设置列表
        <el-form :inline="true" class="demo-form-inline">
            <el-form-item>
                <el-input  v-model="searchObj.hosname" placeholder="医院名称"/>
            </el-form-item>
            <el-form-item>
                <el-input v-model="searchObj.hoscode" placeholder="医院编号"/>
            </el-form-item>
            <el-button type="primary" icon="el-icon-search" @click="getList()">查询</el-button>
            <!-- <el-button type="default" @click="resetData()">清空</el-button> -->
        </el-form>

在这里插入图片描述

前端 删除

  1. 添加删除按钮
  2. 编写调用删除的方法,得到删除id的值
  3. 在api文件夹的 hospset.js文件定义操作的接口路径
  4. 调用定义的接口,实现具体功能

1.在页面利用element-ui添加删除按钮

      <!-- 删除按钮 -->
      <el-table-column label="操作" width="280" align="center">
        <template slot-scope="scope">
          <el-button
            type="danger"
            size="mini"
            icon="el-icon-delete"
            @click="removeDataById(scope.row.id)">
          </el-button>
        </template>
      </el-table-column>

2.在list.vue编写调用删除的方法,得到删除id的值
点击按钮,弹窗 确定or取消
确定 调用删除接口,刷新页面(此为刷新到第一页)

    //删除医院设置 的方法
    removeDataById(id) {
      // alert(id)
      this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          //确定执行then
          //调用接口
          hospset.deleteHospSet(id).then(response => {
            //提示
            this.$message({
              type: "success",
              message: "删除成功!"
            })
            //刷新页面
            this.getList(1)
          })
        })
    }

3.在api文件夹的 hospset.js文件定义操作的接口路径
在这里插入图片描述

前端 批量删除

在每条数据前加一个复选框 ,将选择的id传入到方法中

如何得到选中的 id 值?
在复选框位置绑定事件

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
多个值如何取?

锁定和取消锁定

在这里插入图片描述

添加设置

添加成功,跳转到列表页面

在这里插入图片描述

回显及修改

回显 --> 根据id查询
添加路由
在这里插入图片描述
hospset.js

  //设置id查询
  getHospSet(id){
    return request({
      url: `/admin/hosp/hospitalSet/getHospSet/${id}`,
      method: 'get' 
    })
  },
  //修改设置
  updateHosplSet(hospitalSet){
    return request({
      url: `/admin/hosp/hospitalSet/updateHospitalSet`,
      method: 'post' ,
      data:hospitalSet
    })
  },

add.vue

        //根据id查询
        getHospitalSet(id){
            hospset.getHospSet(id)
                .then(response=>{
                    this.hospitalSet=response.data
                })
        },
        //修改
        update(){
            hospset.updateHosplSet(this.hospitalSet)//要用当前变量和它的值要加this
                .then(response=>{
                    //
                    this.$message({
                        type:'success',
                        message:'修改成功!'
                    })
                    //跳转
                    this.$router.push({path:'/hospSet/list'})
                })
        },
        //判断添加还是修改  没有id做添加,有id做修改操作
        saveOrUpdate(){
            if(!this.hospitalSet.id){
                this.save()
            }else{
                this.update()
            }
        }

回显后 点击添加 数据没有清除的问题

问题:vue-router导航切换 时,如果两个路由都渲染同个组件,
组件的生命周期方法(created或者mounted)不会再被调用, 组件会被重用,显示上一个路由渲染出来的自建

解决方案:可以简单的在 router-view上加上一个唯一的key,来保证路由切换时都会重新触发生命周期方法,确保组件被重新初始化。

在这里插入图片描述
在这里插入图片描述

3 数据字典

3.1 后端基础搭建

参照 service-hosp 修改
端口号为8202,数据库yygh_cmn
在这里插入图片描述
在这里插入图片描述

@Api("数据字典接口")
@RestController
@CrossOrigin
@RequestMapping("/admin/cmn/dict")
public class DictController {
    @Autowired
    private DictService dictService;

    //根据数据id查询子数据列表
    @ApiOperation(value = "根据数据id查询子数据列表")
    @GetMapping("findChildData/{id}")
    public Result findChildData(@PathVariable Long id){
        List<Dict> list =dictService.findChlidData(id);
        return Result.ok(list);
    }
}
@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {
    //MP已经实现注入

    根据数据id查询子数据列表
    @Override
    public List<Dict> findChlidData(Long id) {
        QueryWrapper<Dict> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id", id);

        List<Dict> dictList = baseMapper.selectList(wrapper);
        /*
        遍历list集合,根据每个对象中的id值查询其下面有没有子节点或子数据
        将其返回值 setHasChildren(isChild)
         */
        for (Dict dict : dictList) {
            Long dictId = dict.getId();
            boolean isChild=this.isChildren(dictId);
            dict.setHasChildren(isChild);
        }
        return dictList;
    }
    //判断id下面是否有子节点
    private boolean isChildren(Long id) {
        QueryWrapper<Dict> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id", id);
        Integer count = baseMapper.selectCount(wrapper);//值>0 , 有数据
        // >0 返回true
        return count>0;
    }
}

3.2 前端基础搭建

在router的index.js添加路由
在这里插入图片描述

创建api文件dict.js 和视图文件
在这里插入图片描述
api/dict.js

import request from '@/utils/request'

export default{
  //数据字典列表
  dictList(id){
    return request({
      url: `/admin/cmn/dict/findChildData/${id}`,
      method: 'get',
    })
  },
  
}

dict/list.vue

<template>
    <div class="app-container">
        <el-table
        :data="list"
        style="width: 100%"
        row-key="id"
        border
        lazy
        :load="getChildrens"
        :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
            <el-table-column label="名称" width="230" align="left">
            <template slot-scope="scope">
            <span>{{ scope.row.name }}</span>
            </template>
            </el-table-column>

            <el-table-column label="编码" width="220">
            <template slot-scope="{row}">
                    {{ row.dictCode }}
            </template>
            </el-table-column>
            <el-table-column label="值" width="230" align="left">
            <template slot-scope="scope">
            <span>{{ scope.row.value }}</span>
            </template>
            </el-table-column>
            <el-table-column label="创建时间" align="center">
            <template slot-scope="scope">
            <span>{{ scope.row.createTime }}</span>
            </template>
            </el-table-column>
        </el-table>
    </div>

    
</template>

<script>
import dict from '@/api/dict'

export default{
    data(){
        return{
            list:[] //数据字典列表数组
        }
    },
    created(){
        this.getDictList(1)
    },
    methods:{
        //数据字典列表
        getDictList(id){
            dict.dictList(id)
                .then(response=>{
                    this.list=response.data
                })
        },
        getChildrens(tree,treeNode,resolve){
            dict.dictList(tree.id).then(response => {
                resolve(response.data)
            })
      }
    }
    
}
</script>

注意前端页面若在没有报错的情况下 也没有展示出来分级菜单 -->升级下element-ui的版本
在这里插入图片描述

3.3 EasyExcel集成

    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.1</version>
        </dependency>
    </dependencies>

测试读写

往 excel 中写数据
@Data
public class UserData {

    @ExcelProperty("用户编号")
    private int uid;

    @ExcelProperty("用户名称")
    private String username;
}
public class TestWrite {
    public static void main(String[] args) {
        //构建数据list集合
        List<UserData> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            UserData data = new UserData();
            data.setUid(i);
            data.setUsername("lucy"+i);
            list.add(data);
        }


        //设置excel文件路径和文件名称
        String fileName="D:\\excel\\01.xlsx";

        //调用方法实现写操作
        EasyExcel.write(fileName,UserData.class).sheet("用户信息")
                .doWrite(list);
    }
}

在这里插入图片描述

从excel读数据

在这里插入图片描述

需要写一个监听器

public class ExcelListener extends AnalysisEventListener<UserData> {
    //一行一行的读取excel内容,从第二行读取
    @Override
    public void invoke(UserData userData, AnalysisContext analysisContext) {
        System.out.println(userData);
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头信息"+headMap);
    }

    //读取后执行
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

public class TestRead {
    public static void main(String[] args) {
        //设置excel文件路径和文件名称
        String fileName="D:\\excel\\01.xlsx";

        //调用方法实现读取操作
        EasyExcel.read(fileName,UserData.class,new ExcelListener()).sheet().doRead();
    }
}

在这里插入图片描述

3.4 数据字典导出

添加导出实体

package com.cn.yygh.vo.cmn;

@Data
public class DictEeVo {

	@ExcelProperty(value = "id" ,index = 0)
	private Long id;

	@ExcelProperty(value = "上级id" ,index = 1)
	private Long parentId;

	@ExcelProperty(value = "名称" ,index = 2)
	private String name;

	@ExcelProperty(value = "值" ,index = 3)
	private String value;

	@ExcelProperty(value = "编码" ,index = 4)
	private String dictCode;

}

controller

    //导出数据字典接口
    @GetMapping("exportData")
    public void exportDict(HttpServletResponse response){
        dictService.exportDictData(response);
    }

service方法

    //导出数据字典接口
    @Override
    public void exportDictData(HttpServletResponse response) {
        //设置下载信息
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = "dict";
        response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
        //查询数据库
        List<Dict> dictList = baseMapper.selectList(null);
        //Dict ---> DictEeVo  遍历dictList后得到Dict对象,把每个Dict对象中的内容复制到DictEeVo中
        List<DictEeVo> dictVoList = new ArrayList<>();
        for (Dict dict : dictList) {
            DictEeVo dictEeVo = new DictEeVo();
//            dictEeVo.setId(dict.getId());
            BeanUtils.copyProperties(dict,dictEeVo,DictEeVo.class);
            dictVoList.add(dictEeVo);
        }
        //调用方法进行写操作
        try {
            EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("dict")
                    .doWrite(dictVoList);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

导出前端按钮

        <div class="el-toolbar">
            <div class="el-toolbar-body" style="justify-content: flex-start;">
                <a href="http://localhost:8202/admin/cmn/dict/exportData" target="_blank">
                    <el-button type="text" @click="exportData"><i class="fa fa-plus"/> 导出</el-button>
                </a>
                <el-button type="text" @click="importData"><i class="fa fa-plus"/> 导入</el-button>
            </div>
        </div>

添加导出方法

exportData() {
	window.location.href = 'http://localhost:8202/admin/cmn/dict/exportData'
}

3.5 数据字典导入

创建回调监听器

public class DictListener extends AnalysisEventListener<DictEeVo> {
    private DictMapper dictMapper;

    public DictListener(DictMapper dictMapper) {
        this.dictMapper = dictMapper;
    }

    //一行一行读取
    @Override
    public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {
        //调用方法添加数据库
        Dict dict = new Dict();
        BeanUtils.copyProperties(dictEeVo,dict);
        dictMapper.insert(dict);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

controller

    //导入数据字典
    @PostMapping("importData")
    public Result importDict(MultipartFile file){
        dictService.importDictData(file);
        return Result.ok();
    }

service

    //导入数据字典
    @Override
    public void importDictData(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(),DictEeVo.class,new DictListener(baseMapper)).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

前端按钮和弹出层的添加

在这里插入图片描述

        <!-- 导入弹出层 -->
        <el-dialog title="导入" :visible.sync="dialogImportVisible" width="480px">
            <el-form label-position="right" label-width="170px">

            <el-form-item label="文件">
            <el-upload
            :multiple="false"
            :on-success="onUploadSuccess"
            :action="'http://localhost:8202/admin/cmn/dict/importData'"
            class="upload-demo">
            <el-button size="small" type="primary">点击上传</el-button>
            <div slot="tip" class="el-upload__tip">只能上传excel文件,且不超过500kb</div>
            </el-upload>
            </el-form-item>

            </el-form>
            <div slot="footer" class="dialog-footer">
            <el-button @click="dialogImportVisible = false">
                取消
            </el-button>
            </div>
        </el-dialog>

添加方法

        //导入数据字典
        importData(){
            this.dialogImportVisible = true
        },
        //上传成功调用
        onUploadSuccess(){
            //关闭弹窗
            this.dialogImportVisible = false
            //刷新页面
            this.getDictList(1)
        },

在这里插入图片描述

3.6添加缓存 SpringCache+redis

创建配置类redis.config

package com.cn.yygh.common.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.lang.reflect.Method;
import java.time.Duration;

@Configuration
@EnableCaching  //开启缓存
public class RedisConfig {
    /**
     * 自定义key规则  redis结构  k,v
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

    /**
     * 设置RedisTemplate规则
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        //序列号key value
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 设置CacheManager缓存规则
     * @param factory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }


}

在具体服务中添加redis (在相应服务的配置文件中添加redis路径)

#reids 配置
spring.redis.host=192.168.64.128
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000

spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0

改造DictServiceImpl类方法

在这里插入图片描述
在这里插入图片描述

测试

在这里插入图片描述
由于是懒加载,先只查询当前内容
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值