03. 医院设置_后端

1、Swagger2 测试工具

编写和维护接口文档是每个程序员的职责,根据Swagger2可以快速帮助我们编写最新的API接口文档,再也不用担心开会前仍忙于整理各种资料了,间接提升了团队开发的沟通效率。

swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。

@Api:修饰整个类,描述Controller的作用

@ApiOperation:描述一个类的一个方法,或者说一个接口

@ApiParam:单个参数描述

@ApiModel:用对象来接收参数

@ApiModelProperty:用对象接收参数时,描述对象的一个字段

@ApiImplicitParam:一个请求参数

@ApiImplicitParams:多个请求参数

a. 引入依赖

在common模块pom.xml引入Swagger2依赖



    io.springfox
    springfox-swagger2


    io.springfox
    springfox-swagger-ui
b. 添加swagger2配置类

在service-util模块添加 com.atguigu.yygh.common.config.Swagger2Config 配置类

package com.atguigu.yygh.common.config;

/**
 * Swagger2 配置信息
 */
@Configuration
@EnableSwagger2
public class Swagger2Config {

    @Bean
    public Docket webApiConfig() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                // 只显示api路径下的页面
                .paths(Predicates.and(PathSelectors.regex("/api/.*")))
                .build();
    }

    @Bean
    public Docket adminApiConfig() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("adminApi")
                .apiInfo(adminApiInfo())
                .select()
                // 只显示 admin 路径下的页面
                .paths(Predicates.and(PathSelectors.regex("/admin/.*")))
                .build();
    }

    private ApiInfo webApiInfo() {
        return new ApiInfoBuilder()
                .title("网站-API文档")
                .description("本文档描述了网站微服务接口定义")
                .version("1.0")
                .contact(new Contact("atguigu","http://atguigu.com","[email protected]"))
                .build();
    }

    private ApiInfo adminApiInfo() {
        return new ApiInfoBuilder()
                .title("后台管理系统——API文档")
                .description("本文档描述了后台管理系统微服务接口定义")
                .version("1.0")
                .contact(new Contact("atguigu", "http://atguigu.com", "[email protected]"))
                .build();

    }
}
c. 在启动类上添加包扫描

因为Swagger2Config 和启动类不在一个模块下,引入进来之后,需要添加组件扫描。否则不能访问SwaggerUI界面

@SpringBootApplication
@ComponentScan(basePackages = "com.atguigu")
public class ServiceHospApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceHospApplication.class, args);
    }
}
2、搭建医院模块(service_hosp)

医院设置主要是用来保存开通医院的一些基本信息,每个医院一条信息,保存了医院编号(平台分配,全局唯一)和接口调用相关的签名key等信息,是整个流程的第一步,只有开通了医院设置信息,才可以上传医院相关信息。

我们所开发的功能就是基于单表的一个CRUD、锁定/解锁和发送签名信息这些基本功能。

03. 医院设置_后端_第1张图片

a. 创建数据库

表结构:

03. 医院设置_后端_第2张图片

hosname: 医院名称

hoscode: 医院编号(平台分配,全局唯一,api接口必填信息)

api_url: 医院回调的基础url(如:预约下单,我们要调用该地址去医院下单)

sign_key: 双方api接口调用的签名key,有平台生成

contacts_name: 医院联系人姓名

contacts_phone: 医院联系人手机

status: 状态(锁定/解锁)

#
# Database "yygh_hosp"
#

CREATE DATABASE IF NOT EXISTS `yygh_hosp` CHARACTER SET utf8mb4;
USE `yygh_hosp`;

#
# Structure for table "hospital_set"
#

CREATE TABLE `hospital_set` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `hosname` varchar(100) DEFAULT NULL COMMENT '医院名称',
  `hoscode` varchar(30) DEFAULT NULL COMMENT '医院编号',
  `api_url` varchar(100) DEFAULT NULL COMMENT 'api基础路径',
  `sign_key` varchar(50) DEFAULT NULL COMMENT '签名秘钥',
  `contacts_name` varchar(20) DEFAULT NULL COMMENT '联系人',
  `contacts_phone` varchar(11) DEFAULT NULL COMMENT '联系人手机',
  `status` tinyint(3) NOT NULL DEFAULT '0' COMMENT '状态',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` tinyint(3) NOT NULL DEFAULT '0' COMMENT '逻辑删除(1:已删除,0:未删除)',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_hoscode` (`hoscode`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='医院设置表';
b. service_hosp.pom

在service下创建service_hosp模块


    com.atguigu.yygh
    service
    0.0.1-SNAPSHOT


com.atguigu.yygh
service_hosp
0.0.1-SNAPSHOT
jar
service-hosp
service-hosp





    service-hosp
    
        
            org.springframework.boot
            spring-boot-maven-plugin
        
    
c. application.yaml
# 服务端口
server:
  port: 8201

spring:
  application:
    # 服务名
    name: service-hosp
  # 环境设置:dev、test、prod
  profiles:
    active: dev
  # 数据库连接
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/yygh_hosp?characterEncoding=utf-8&useSSL=false
    username: root
    password: 0903he0419

  # 返回json的全局时间格式
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

mybatis-plus:
  #配置mapper xml文件的路径
  mapper-locations: com/atguigu/yygh/hosp/mapper/xml/*.xml
d. 创建配置类

在com.atguigu.yygh.hosp.config 创建HospConfig 配置类

将mapper扫描放在配置类上

@Configuration
@MapperScan("com.atguigu.yygh.hosp.mapper")
public class HospConfig {
    // Mybatis-Plus 分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}
e. 导入实体类

BaseEntity

@Data
public class BaseEntity implements Serializable {

    @ApiModelProperty(value = "id")
    @TableId(type = IdType.AUTO)
    private Long id;

    @ApiModelProperty(value = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField("create_time")
    private Date createTime;

    @ApiModelProperty(value = "更新时间")
    @TableField("update_time")
    private Date updateTime;

    @ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)")
    @TableLogic
    @TableField("is_deleted")
    private Integer isDeleted;

    @ApiModelProperty(value = "其他参数")
    @TableField(exist = false)
    private Map param = new HashMap<>();
}

com.atguigu.yygh.model.hosp.HospitalSet

@Data
@ApiModel(description = "医院设置")
@TableName("hospital_set")
public class HospitalSet extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "医院名称")
    @TableField("hosname")
    private String hosname;

    @ApiModelProperty(value = "医院编号")
    @TableField("hoscode")
    private String hoscode;

    @ApiModelProperty(value = "api基础路径")
    @TableField("api_url")
    private String apiUrl;

    @ApiModelProperty(value = "签名秘钥")
    @TableField("sign_key")
    private String signKey;

    @ApiModelProperty(value = "联系人姓名")
    @TableField("contacts_name")
    private String contactsName;

    @ApiModelProperty(value = "联系人手机")
    @TableField("contacts_phone")
    private String contactsPhone;

    @ApiModelProperty(value = "状态")
    @TableField("status")
    private Integer status;

}

HospitalSetVo

@Data
public class HospitalSetQueryVo {

    @ApiModelProperty(value = "医院名称")
    private String hosname;

    @ApiModelProperty(value = "医院编号")
    private String hoscode;
}
f. 创建统一返回结果类

Result

/**
 * 全局统一返回结果类
 */
@Data
@ApiModel(value = "全局统一返回结果")
public class Result {

    @ApiModelProperty(value = "返回码")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String message;

    @ApiModelProperty(value = "返回数据")
    private T data;

    public Result(){}

    protected static  Result build(T data) {
        Result result = new Result();
        if (data != null)
            result.setData(data);
        return result;
    }

    public static  Result build(T body, ResultCodeEnum resultCodeEnum) {
        Result result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }

    public static  Result build(Integer code, String message) {
        Result result = build(null);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    public static Result ok(){
        return Result.ok(null);
    }

    /**
     * 操作成功
     * @param data
     * @param 
     * @return
     */
    public static Result ok(T data){
        Result result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }

    public static Result fail(){
        return Result.fail(null);
    }

    /**
     * 操作失败
     * @param data
     * @param 
     * @return
     */
    public static Result fail(T data){
        Result result = build(data);
        return build(data, ResultCodeEnum.FAIL);
    }

    public Result message(String msg){
        this.setMessage(msg);
        return this;
    }

    public Result code(Integer code){
        this.setCode(code);
        return this;
    }

    public boolean isOk() {
        if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
            return true;
        }
        return false;
    }
}

ResultCodeEnum

/**
 * 统一返回结果状态信息类
 */
@Getter
public enum ResultCodeEnum {

    SUCCESS(200,"成功"),
    FAIL(201, "失败"),
    PARAM_ERROR( 202, "参数不正确"),
    SERVICE_ERROR(203, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    DATA_UPDATE_ERROR(205, "数据版本异常"),

    LOGIN_AUTH(208, "未登陆"),
    PERMISSION(209, "没有权限"),

    CODE_ERROR(210, "验证码错误"),
//    LOGIN_MOBLE_ERROR(211, "账号不正确"),
    LOGIN_DISABLED_ERROR(212, "改用户已被禁用"),
    REGISTER_MOBLE_ERROR(213, "手机号已被使用"),
    LOGIN_AURH(214, "需要登录"),
    LOGIN_ACL(215, "没有权限"),

    URL_ENCODE_ERROR( 216, "URL编码失败"),
    ILLEGAL_CALLBACK_REQUEST_ERROR( 217, "非法回调请求"),
    FETCH_ACCESSTOKEN_FAILD( 218, "获取accessToken失败"),
    FETCH_USERINFO_ERROR( 219, "获取用户信息失败"),
    //LOGIN_ERROR( 23005, "登录失败"),

    PAY_RUN(220, "支付中"),
    CANCEL_ORDER_FAIL(225, "取消订单失败"),
    CANCEL_ORDER_NO(225, "不能取消预约"),

    HOSCODE_EXIST(230, "医院编号已经存在"),
    NUMBER_NO(240, "可预约号不足"),
    TIME_NO(250, "当前时间不可以预约"),

    SIGN_ERROR(300, "签名错误"),
    HOSPITAL_OPEN(310, "医院未开通,暂时不能访问"),
    HOSPITAL_LOCK(320, "医院被锁定,暂时不能访问"),
    ;

    private Integer code;
    private String message;

    private ResultCodeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
g. Mapper 层

com.atguigu.yygh.model.hosp.mapper

@Mapper
public interface HospitalSetMapper extends BaseMapper {
}

com.atguigu.yygh.model.hosp.mapper.xml





h. Service 层

com.atguigu.yygh.model.hosp.service

public interface HospitalSetService extends IService {
}

com.atguigu.yygh.model.hosp.service.impl

@Service
public class HospitalSetServiceImpl extends ServiceImpl implements HospitalSetService {
    @Autowired
    private HospitalSetMapper hospitalSetMapper;
}
i. Controller 层

com.atguigu.yygh.model.hosp.controller

package com.atguigu.yygh.hosp.controller;

@Api(tags = "医院设置管理")
@RestController
@RequestMapping("/admin/hosp/hospitalSet")
public class HospitalSetController {
    @Autowired
    private HospitalSetService hospitalSetService;

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

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

    /*
    * 3、条件查询带分页
    * */
    @ApiOperation(value = "条件查询带分页")
    @PostMapping("findPageHospSet/{current}/{limit}")
    public Result findPageHospSet(@PathVariable long current,
                                  @PathVariable long limit,
                                  @RequestBody(required = false)
                                      HospitalSetQueryVo hospitalSetQueryVo
                                  ) {
        // 创建 page 对象,传递当前页,每页记录数
        Page page = new Page<>(current, limit);
        QueryWrapper 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("hosocde", hospitalSetQueryVo.getHoscode());
        }
        // 调用方法实现分页查询
        Page pageHospitalSet = hospitalSetService.page(page, wrapper);
        // 返回结果
        return Result.ok(pageHospitalSet);
    }

    /*
    * 4、添加医院设置
    * */
    @ApiOperation(value = "添加医院设置")
    @PostMapping("saveHospitalSet")
    public Result saveHospitalSet(@RequestBody HospitalSet hospitalSet) {
        // 设置状态:1 使用,0 不能使用
        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();
        }
    }

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

    /*
    * 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();
        }
    }

    /*
    * 7、批量删除医院设置
    * */
    @ApiOperation(value = "批量删除医院设置")
    @DeleteMapping("batchRemove")
    public Result batchRemoveHospitalSet(@RequestBody List idList) {
        boolean flag = hospitalSetService.removeByIds(idList);
        if (flag) {
            return Result.ok();
        } else {
            return Result.fail();
        }
    }

    /*
    * 8、医院设置锁定与解锁
    * */
    @ApiOperation(value = "医院设置锁定与解锁")
    @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();
    }

    /*
    * 9、发送签名秘钥
    * */
    @PutMapping("sendKey/{id}")
    public Result lockHospitalSet(@PathVariable Long id) {
        HospitalSet hospitalSet = hospitalSetService.getById(id);
        String signKey = hospitalSet.getSignKey();
        String hoscode = hospitalSet.getHoscode();
        // TODO 发送短信
        return Result.ok();
    }
}
j. 统一异常处理

在common-util模块添加自定义异常处理类——YyghException

@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() +
                '}';
    }
}

在common-util模块添加全局异常处理类——GlobalExceptionHandler

/*
* 全局异常处理类
* */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public Result error(Exception e) {
        e.printStackTrace();
        return Result.fail();
    }

    /*
    * 自定义异常处理
    * */
    @ExceptionHandler(YyghException.class)
    public Result error(YyghException e) {
        e.printStackTrace();
        System.out.println(e.getCode() + " : " + e.getMessage());
        return Result.build(e.getCode(), e.getMessage());
    }
}

在controller中测试全局异常是否生效:访问根据id获取医院设置此接口测试自定义异常

/*
* 5、根据id获取医院设置
* */
@ApiOperation(value = "根据id获取医院设置")
@GetMapping("getHospSet/{id}")
public Result getHospSet(@PathVariable Long id) {

    try {
        // 模拟异常
        int a = 1 / 0;
    } catch (Exception e) {
        throw new YyghException("失败了呀", 2002);
    }
    HospitalSet hospitalSet = hospitalSetService.getById(id);
    return Result.ok(hospitalSet);
}
k. 统一日志处理

日志记录器(Logger)的行为是分等级的。如下表所示:分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL

默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别

# 设置日志级别
logging:
  level:
    root: debug
  • 这种方式只能将日志打印在控制台上

resources/logback-spring.xml



  
  
  
  
  logback
  
  
  
  
  
  
  
  
  
  
  
  
    
    
    
      INFO
    
    
      ${CONSOLE_LOG_PATTERN}
      
      UTF-8
    
  
  
  
  
    
    ${log.path}/log_info.log
    
    
      %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
      UTF-8
    
    
    
      
      ${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log
      
        100MB
      
      
      15
    
    
    
      INFO
      ACCEPT
      DENY
    
  

  
  
    
    ${log.path}/log_warn.log
    
    
      %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
            UTF-8 
        
        
        
            ${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log
            
                100MB
            
            
            15
        
        
        
            warn
            ACCEPT
            DENY
        
    


    
    
        
        ${log.path}/log_error.log
        
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
            UTF-8 
        
        
        
            ${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log
            
                100MB
            
            
            15
        
        
        
            ERROR
            ACCEPT
            DENY
        
    

    
    
    
    
        
        

        
        
            
            
            
            
        
    


    
    

        
            
            
            
            
            
        
    

你可能感兴趣的:(尚医通_后端项目,Java,spring,boot,spring,cloud)