医院设置模块
需求
-
医院设置主要是用来保存开通医院的一些基本信息,每个医院一条信息,保存了医院编号(平台分配,全局唯一)和接口调用相关的签名key等信息,是整个流程的第一步,只有开通了医院设置信息,才可以上传医院相关信息。
-
我们所开发的功能就是基于单表的一个CRUD、锁定/解锁和发送签名信息这些基本功能。
表结构
医院设置模块开发
- 搭建service-hosp模块
该模块设置为maven module,设置父模块是service模块。
- 配置application.properties文件(包含目前使用的)
# 服务端口
server.port=8201
# 服务名
spring.application.name=service-hosp
# 环境设置:dev、test、prod
spring.profiles.active=dev
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/yygh_hosp?characterEncoding=utf-8&useSSL=false
spring.datasource.username=admin_hosp
spring.datasource.password=123456
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#配置mapper xml文件的路径
#mybatis-plus.mapper-locations=classpath:com/atguigu/yygh/mapper/xml/*.xml
mybatis-plus.mapper-locations=classpath:com/yogie/yygh/mapper/xml/*.xml
- 添加启动类
@SpringBootApplication
public class ServiceHospApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceHospApplication.class, args);
}
}
- 实体类
(1)基础实体类
/**
* 基础实体类
*/
@Data
public class BaseEntity implements Serializable {
@ApiModelProperty(value="id")
@TableId(type = IdType.AUTO)
private Long id;
@ApiModelProperty(value = "创建时间")
@TableField("create_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
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<String, Object> param = new HashMap<>();
}
(2)医院设置实体类
/**
* 医院设置实体类
*/
@ApiModel(description = "医院设置")
@Data
@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;
}
(2)医院设置查询实体类HospitalSetQueryVo
/**
* 医院设置查询实体类:根据hosname和hoscode查询,可单选、不选
*/
@Data
public class vo {
@ApiModelProperty(value = "医院名称")
private String hosname;
@ApiModelProperty(value = "医院编号")
private String hoscode;
}
- 接口开发
(1)Mapper
public interface HospitalSetMapper extends BaseMapper<HospitalSet> {
}
/**
* 医院配置类,扫描Mapper
*/
@Configuration
@MapperScan("com.yogie.yygh.hosp.mapper")
public class HospitalConfig {
}
(2)Service
/**
* 医院设置service
*/
public interface HospitalSetService extends IService<HospitalSet> {
}
/**
* service实现类
*/
@Service
public class HospitalSetServiceImpl extends ServiceImpl<HospitalSetMapper, HospitalSet> implements HospitalSetService {
}
(3)Controller
/**
* 医院设置控制器类
*/
@Api(tags = "医院设置管理")
@RestController
@RequestMapping("/admin/hosp/hospitalSet")
public class HospitalSetController {
// 注入service
@Autowired
private HospitalSetService hospitalSetService;
/**
* 查询医院设置表所有信息
*/
@ApiOperation(value = "获取所有医院设置")
@GetMapping("findAll")
public List findAllHospitalSet() {
// 调用service方法
List<HospitalSet> list = hospitalSetService.list();
return list;
}
/**
* 逻辑删除医院配置
*/
@ApiOperation(value = "逻辑删除医院设置")
@DeleteMapping("{id}")
public Boolean removeHospSet(@PathVariable Long id) {
return hospitalSetService.removeById(id);
}
/**
* 条件查询带分页
*/
@PostMapping("findPageHospSet/{current}/{limit}")
public Page<HospitalSet> 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", hosname); // 根据名称模糊查询
}
if (!StringUtils.isEmpty(hoscode)) {
wrapper.eq("hoscode", hoscode); // 根据编号精确查询
}
// 调用方法实现分页查询(不使用分页插件,为内存分页;如果后期添加了分页插件,才是物理分页)
Page<HospitalSet> pageHospitalSet = hospitalSetService.page(page, wrapper);
return pageHospitalSet;
}
/**
* 添加医院设置
*/
@PostMapping("saveHospitalSet")
public Boolean saveHospitalSet(@RequestBody HospitalSet hospitalSet) {
// 设置状态:1使用 0不能使用(可以通过mybatis-plus的自动填充实现)
hospitalSet.setStatus(1);
// 签名密钥
Random random = new Random();
hospitalSet.setSignKey(MD5.encrypt(System.currentTimeMillis() + "" + random.nextInt(1000)));
return hospitalSetService.save(hospitalSet);
}
/**
* 根据id获取医院设置
*/
@GetMapping("getHospSet/{id}")
public HospitalSet getHospSet(@PathVariable Long id) {
return hospitalSetService.getById(id);
}
/**
* 修改医院设置
*/
@PutMapping("updateHospitalSet")
public Boolean updateHospitalSet(@RequestBody HospitalSet hospitalSet) {
return hospitalSetService.updateById(hospitalSet);
}
/**
* 批量删除医院设置
*/
@DeleteMapping("batchRemove")
public Boolean batchRemoveHospitalSet(@RequestBody List<Long> idList) {
return hospitalSetService.removeByIds(idList);
}
/**
* 医院设置锁定和解锁:修改状态
*/
@PutMapping("lockHospitalSet/{id}/{status}")
public Result<Object> lockHospitalSet(@PathVariable Long id, @PathVariable Integer status) {
// 根据id查询医院设置信息
HospitalSet hospitalSet = hospitalSetService.getById(id);
// 设置状态
hospitalSet.setStatus(status);
// 更新
boolean flag = hospitalSetService.updateById(hospitalSet);
return flag ? Result.success() : Result.fail();
}
/**
* 发送签名key:医院信息配置后,可以通过短信的形式发送医院编号与签名给联系人,联系人拿到该信息就可以参考《尚医通API接口文档.docx》对接接口了
*/
@PutMapping("sendKey/{id}")
public Result<Object> sendKey(@PathVariable Long id) {
HospitalSet hospitalSet = hospitalSetService.getById(id);
String signKey = hospitalSet.getSignKey();
String hoscode = hospitalSet.getHoscode();
// TODO 发送短信
return Result.success();
}
}
MD5为MD5加密工具类
- 整合Swagger2进行接口测试
(1)Swagger配置类
/**
* 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("yogie", "http://yogie.com", "1539682936@qq.com"))
.build();
}
private ApiInfo adminApiInfo() {
return new ApiInfoBuilder()
.title("后台管理系统-API文档")
.description("本文档描述了后台管理系统微服务接口定义")
.version("1.0")
.contact(new Contact("yogie", "http://yogie.com", "1539682936@qq.com"))
.build();
}
}
(2)注解
@Api:修饰整个类,描述Controller的作用
@ApiOperation:描述一个类的一个方法,或者说一个接口
@ApiParam:单个参数描述
@ApiModel:用对象来接收参数
@ApiModelProperty:用对象接收参数时,描述对象的一个字段
@ApiImplicitParam:一个请求参数
@ApiImplicitParams:多个请求参数
- 统一返回信息-----封装结果集
(1)统一返回结果状态信息类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;
}
}
(2)统一返回结果类Result
/**
* 全局统一返回结果类
*/
@Data
@ApiModel(value = "全局统一返回结果")
public class Result<T> {
@ApiModelProperty(value = "返回码")
private Integer code;
@ApiModelProperty(value = "返回信息")
private String message;
@ApiModelProperty(value = "返回数据")
private T data;
public Result(){}
protected static <T> Result<T> build(T data) {
Result<T> result = new Result<>();
if (data != null) {
result.setData(data);
}
return result;
}
public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
Result<T> result = build(body);
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
return result;
}
public static <T> Result<T> build(Integer code, String message) {
Result<T> result = build(null);
result.setCode(code);
result.setMessage(message);
return result;
}
/**
* 操作成功,无数据返回
* @param <T>
* @return
*/
public static <T> Result<T> success() {
return Result.success(null);
}
/**
* 操作成功
* @param data
* @param <T>
* @return
*/
public static <T> Result<T> success(T data) {
//Result<T> result = build(data);
return build(data, ResultCodeEnum.SUCCESS);
}
/**
* 操作失败,无数据返回
* @param <T>
* @return
*/
public static <T> Result<T> fail() {
return Result.fail(null);
}
/**
* 操作失败
* @param data
* @param <T>
* @return
*/
public static <T> Result<T> fail(T data) {
return build(data, ResultCodeEnum.FAIL);
}
public Result<T> message(String message) {
this.setMessage(message);
return this;
}
public Result<T> code(Integer code) {
this.setCode(code);
return this;
}
public Boolean isSuccess() {
if (this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
return true;
}
return false;
}
}
- 改造Controller,修改返回信息
主要内容:将已经实现的接口的返回值用Result封装
- 全局统一异常
(1)自定义异常类
/**
* 自定义全局异常类
*/
@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() +
'}';
}
}
(2)异常处理器,可以处理Exception和自定义异常
/**
* 全局异常处理器
*/
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理Exception
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Result<Object> error(Exception e) {
e.printStackTrace();
return Result.fail();
}
/**
* 处理YyghException
* @param e
* @return
*/
@ExceptionHandler(YyghException.class)
@ResponseBody
public Result<Object> error(YyghException e) {
e.printStackTrace();
// 根据异常抛出时传递的参数,创建Result对象
return Result.build(e.getCode(), e.getMessage());
}
}
- 日志配置
resources/logback-spring.xml
配置logback相关信息
注:不同模块直接存在依赖的,需要在pom文件中引入模块依赖