Back-end-data interface-upload hospital information environment construction and implementation

Back-end-data interface-upload hospital information interface environment to build

Refer to "Shangyitong API Interface Document.docx" Business Interface 4.1 Upload Hospital
Refer to "Hospital Interface Simulation System.docx" for interface testing and data upload

1. Add public basic classes

1.1, add basic tools

Insert picture description here


HttpUtil:

package com.study.yygh.common.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 *
 */
@Slf4j
public final class HttpUtil {

	static final String POST = "POST";
	static final String GET = "GET";
	static final int CONN_TIMEOUT = 30000;// ms
	static final int READ_TIMEOUT = 30000;// ms

	/**
	 * post 方式发送http请求.
	 * 
	 * @param strUrl
	 * @param reqData
	 * @return
	 */
	public static byte[] doPost(String strUrl, byte[] reqData) {
		return send(strUrl, POST, reqData);
	}

	/**
	 * get方式发送http请求.
	 * 
	 * @param strUrl
	 * @return
	 */
	public static byte[] doGet(String strUrl) {
		return send(strUrl, GET, null);
	}

	/**
	 * @param strUrl
	 * @param reqmethod
	 * @param reqData
	 * @return
	 */
	public static byte[] send(String strUrl, String reqmethod, byte[] reqData) {
		try {
			URL url = new URL(strUrl);
			HttpURLConnection httpcon = (HttpURLConnection) url.openConnection();
			httpcon.setDoOutput(true);
			httpcon.setDoInput(true);
			httpcon.setUseCaches(false);
			httpcon.setInstanceFollowRedirects(true);
			httpcon.setConnectTimeout(CONN_TIMEOUT);
			httpcon.setReadTimeout(READ_TIMEOUT);
			httpcon.setRequestMethod(reqmethod);
			httpcon.connect();
			if (reqmethod.equalsIgnoreCase(POST)) {
				OutputStream os = httpcon.getOutputStream();
				os.write(reqData);
				os.flush();
				os.close();
			}
			BufferedReader in = new BufferedReader(new InputStreamReader(httpcon.getInputStream(),"utf-8"));
			String inputLine;
			StringBuilder bankXmlBuffer = new StringBuilder();
			while ((inputLine = in.readLine()) != null) {  
			    bankXmlBuffer.append(inputLine);  
			}  
			in.close();  
			httpcon.disconnect();
			return bankXmlBuffer.toString().getBytes();
		} catch (Exception ex) {
			log.error(ex.toString(), ex);
			return null;
		}
	}
	
	/**
	 * 从输入流中读取数据
	 * 
	 * @param inStream
	 * @return
	 * @throws Exception
	 */
	public static byte[] readInputStream(InputStream inStream) throws Exception {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = inStream.read(buffer)) != -1) {
			outStream.write(buffer, 0, len);
		}
		byte[] data = outStream.toByteArray();// 网页的二进制数据
		outStream.close();
		inStream.close();
		return data;
	}
}

HttpRequestHelper:

package com.study.yygh.common.helper;

import com.alibaba.fastjson.JSONObject;
import com.study.yygh.common.utils.HttpUtil;
import com.study.yygh.common.utils.MD5;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

@Slf4j
public class HttpRequestHelper {

    public static void main(String[] args) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("d", "4");
        paramMap.put("b", "2");
        paramMap.put("c", "3");
        paramMap.put("a", "1");
        paramMap.put("timestamp", getTimestamp());
        log.info(getSign(paramMap, "111111111"));
    }

    /**
     *
     * @param paramMap
     * @return
     */
    public static Map<String, Object> switchMap(Map<String, String[]> paramMap) {
        Map<String, Object> resultMap = new HashMap<>();
        for (Map.Entry<String, String[]> param : paramMap.entrySet()) {
            resultMap.put(param.getKey(), param.getValue()[0]);
        }
        return resultMap;
    }

    /**
     * 请求数据获取签名
     * @param paramMap
     * @param signKey
     * @return
     */
    public static String getSign(Map<String, Object> paramMap, String signKey) {
        if(paramMap.containsKey("sign")) {
            paramMap.remove("sign");
        }
        TreeMap<String, Object> sorted = new TreeMap<>(paramMap);
        StringBuilder str = new StringBuilder();
        for (Map.Entry<String, Object> param : sorted.entrySet()) {
            str.append(param.getValue()).append("|");
        }
        str.append(signKey);
        log.info("加密前:" + str.toString());
        String md5Str = MD5.encrypt(str.toString());
        log.info("加密后:" + md5Str);
        return md5Str;
    }

    /**
     * 签名校验
     * @param paramMap
     * @param signKey
     * @return
     */
    public static boolean isSignEquals(Map<String, Object> paramMap, String signKey) {
        String sign = (String)paramMap.get("sign");
        String md5Str = getSign(paramMap, signKey);
        if(!sign.equals(md5Str)) {
            return false;
        }
        return true;
    }

    /**
     * 获取时间戳
     * @return
     */
    public static long getTimestamp() {
        return new Date().getTime();
    }

    /**
     * 封装同步请求
     * @param paramMap
     * @param url
     * @return
     */
    public static JSONObject sendRequest(Map<String, Object> paramMap, String url){
        String result = "";
        try {
            //封装post参数
            StringBuilder postdata = new StringBuilder();
            for (Map.Entry<String, Object> param : paramMap.entrySet()) {
                postdata.append(param.getKey()).append("=")
                        .append(param.getValue()).append("&");
            }
            log.info(String.format("--> 发送请求:post data %1s", postdata));
            byte[] reqData = postdata.toString().getBytes("utf-8");
            byte[] respdata = HttpUtil.doPost(url,reqData);
            result = new String(respdata);
            log.info(String.format("--> 应答结果:result data %1s", result));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return JSONObject.parseObject(result);
    }
}

2. Integrate mongoDB

2.1, add dependency

service-hosp module pom.xml add dependency

<!--springboot整合mongodb-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

2.2, add configuration

Add configuration in application.properties file

# mongoDB
spring.data.mongodb.uri=mongodb://127.0.0.1:27017/yygh_hosp

Description: Change to the ip address of installing mongodb by yourself

3. Upload the basic environment of hospital information

3.1, create an entity class

Insert picture description here

BaseMongoEntity:

package com.study.yygh.model.base;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.data.annotation.Id;
import lombok.Data;
import org.springframework.data.annotation.Transient;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Data
public class BaseMongoEntity implements Serializable {

    @ApiModelProperty(value = "id")
    @Id
    private String id;

    @ApiModelProperty(value = "创建时间")
    private Date createTime;

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

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

    @ApiModelProperty(value = "其他参数")
    @Transient //被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性
    private Map<String,Object> param = new HashMap<>();
}

BookingRule:

package com.study.yygh.model.hosp;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.study.yygh.model.base.BaseEntity;
import com.study.yygh.model.base.BaseMongoEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;

/**
 * <p>
 * RegisterRule
 * </p>
 *
 * @author qy
 */
@Data
@ApiModel(description = "预约规则")
@Document("BookingRule")
public class BookingRule {
	
	@ApiModelProperty(value = "预约周期")
	private Integer cycle;

	@ApiModelProperty(value = "放号时间")
	private String releaseTime;

	@ApiModelProperty(value = "停挂时间")
	private String stopTime;

	@ApiModelProperty(value = "退号截止天数(如:就诊前一天为-1,当天为0)")
	private Integer quitDay;

	@ApiModelProperty(value = "退号时间")
	private String quitTime;

	@ApiModelProperty(value = "预约规则")
	private List<String> rule;

	/**
	 *
	 * @param rule
	 */
	public void setRule(String rule) {
		if(!StringUtils.isEmpty(rule)) {
			this.rule = JSONArray.parseArray(rule, String.class);
		}
	}

}

Hospital:

package com.study.yygh.model.hosp;

import com.alibaba.fastjson.JSONObject;
import com.study.yygh.model.base.BaseEntity;
import com.study.yygh.model.base.BaseMongoEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

/**
 * <p>
 * Hospital
 * </p>
 *
 * @author qy
 */
@Data
@ApiModel(description = "Hospital")
@Document("Hospital")
public class Hospital extends BaseMongoEntity {
	
	private static final long serialVersionUID = 1L;
	
	@ApiModelProperty(value = "医院编号")
	@Indexed(unique = true) //唯一索引
	private String hoscode;

	@ApiModelProperty(value = "医院名称")
	@Indexed //普通索引
	private String hosname;

	@ApiModelProperty(value = "医院类型")
	private String hostype;

	@ApiModelProperty(value = "省code")
	private String provinceCode;

	@ApiModelProperty(value = "市code")
	private String cityCode;

	@ApiModelProperty(value = "区code")
	private String districtCode;

	@ApiModelProperty(value = "详情地址")
	private String address;

	@ApiModelProperty(value = "医院logo")
	private String logoData;

	@ApiModelProperty(value = "医院简介")
	private String intro;

	@ApiModelProperty(value = "坐车路线")
	private String route;

	@ApiModelProperty(value = "状态 0:未上线 1:已上线")
	private Integer status;

	//预约规则
	@ApiModelProperty(value = "预约规则")
	private BookingRule bookingRule;

	public void setBookingRule(String bookingRule) {
		this.bookingRule = JSONObject.parseObject(bookingRule, BookingRule.class);
	}

}

3.2. Create a Repository for using mongoDB

Insert picture description here
@Repository
public interface HospitalRepository extends MongoRepository<Hospital,String> {
}

3.3, create service interface and implementation class

service interface

Insert picture description here
public interface HospitalService {
}

Interface implementation class:

Insert picture description here
@Service
public class HospitalServiceImpl implements HospitalService {

    @Autowired
    private HospitalRepository hospitalRepository;
}

3.4, create a control layer

Insert picture description here
@RestController
@RequestMapping("/api/hosp")
public class ApiController {

    @Autowired
    private HospitalService hospitalService;
}

4. Implementation of uploading hospital information interface

4.1, control layer

Write the control layer method to realize the upload of hospital information.

Insert picture description here
@RestController
@RequestMapping("/api/hosp")
public class ApiController {

    @Autowired
    private HospitalService hospitalService;

    //上传医院信息
    @PostMapping("/saveHospital")
    public Result saveHospital(HttpServletRequest request){
        //获取传递过来的医院信息
        Map<String, String[]> requestMap = request.getParameterMap();
        //将Map<String, String[]> 形式转换成Map<String, Object>方便后续使用
        Map<String, Object>  paramMap = HttpRequestHelper.switchMap(requestMap);
        //调用service方法
        hospitalService.save(paramMap);
        return Result.ok();
    }
}

4.2, business layer

Interface:

Insert picture description here

Implementation class:

Insert picture description here
@Service
public class HospitalServiceImpl implements HospitalService {

    @Autowired
    private HospitalRepository hospitalRepository;

    //上传医院信息
    @Override
    public void save(Map<String, Object> paramMap) {
        //将map集合转换成字符串
        String mapString = JSONObject.toJSONString(paramMap);
        //将字符串转成Hospital对象
        Hospital hospital = JSONObject.parseObject(mapString, Hospital.class);

        //判断MongoDB中是否存在数据
        String hoscode = hospital.getHoscode();
        Hospital hospitalExist = hospitalRepository.getHospitalByHoscode(hoscode);

        //如果存在数据,进行更新
        if(hospitalExist != null){
            hospital.setStatus(hospitalExist.getStatus());
            hospital.setCreateTime(hospitalExist.getCreateTime());
            hospital.setUpdateTime(new Date());
            hospital.setIsDeleted(0);
            hospitalRepository.save(hospital);
        }else{
            //如果不存在数据,进行新增
            hospital.setStatus(0);
            hospital.setCreateTime(new Date());
            hospital.setUpdateTime(new Date());
            hospital.setIsDeleted(0);
            hospitalRepository.save(hospital);
        }
        
    }
}

4.3. Write methods in HospitalRepository for data manipulation

As long as we write the method according to the spring data specification, we don't need to write related sql.

Insert picture description here

Spring Data provides support for mongodb data access, we only need to inherit the MongoRepository class and follow the Spring Data specification.
SpringData method definition specification

Insert picture description here


Insert picture description here


Note:
1. It is not declared casually, but needs to conform to certain specifications.
2. The query method starts with find | read | get
3. When a conditional query is involved, the attribute of the condition is connected with a conditional keyword
4. Pay attention The first letter of the conditional attribute needs to be capitalized.
5. It supports the cascading query of the attribute, but if the current class has a qualified attribute, it will be used first instead of the cascading attribute. If you need to use the cascading attribute, use between the attributes _Force connection

5. Parameter signature verification

5.1. Add signature verification in upload hospital method

When we set up the hospital, we generated the hospital code and signature key for each hospital. Therefore, when verifying the signature, we must dynamically obtain the signature key based on the hospital code, and then perform signature verification.

Check the hospital signature information in the hospital information upload interface:

Insert picture description here
//上传医院信息
@PostMapping("/saveHospital")
public Result saveHospital(HttpServletRequest request){
    //获取传递过来的医院信息
    Map<String, String[]> requestMap = request.getParameterMap();
    //将Map<String, String[]> 形式转换成Map<String, Object>方便后续使用
    Map<String, Object>  paramMap = HttpRequestHelper.switchMap(requestMap);

    //1、获取医院传递过来的签名,签名进行MD5加密
    String hospSign = (String)paramMap.get("sign");

    //2、根据传递过来的医院编码,查询数据库,查询签名
    String hoscode = (String)paramMap.get("hoscode");
    String signKey = hospitalSetService.getSignKey(hoscode);

    //3、把数据库拆线呢的签名进行加密
    String signKeyMD5 = MD5.encrypt(signKey);

    //3、判断签名是否一致
    if(!hospSign.equals(signKeyMD5)){
        throw new YyghException(ResultCodeEnum.SIGN_ERROR);
    }

    //传输过程中 “+” 转换为了“ ”,因此我们要转换回来
    String logoData = (String)paramMap.get("logoData");
    logoData = logoData.replaceAll(" ","+");
    paramMap.put("logoData",logoData);
    
    //调用service方法
    hospitalService.save(paramMap);
    return Result.ok();
}

6. Image base64 encoding

6.1. Picture base64 description

The base64 encoding of a picture is to encode a picture data into a string of strings, and use this string to replace the image address url
in the common base64 picture introduction method in the front-end page:
<img src="data:image/png;base64, iVBORw0...”/>

Advantages
(1) The pictures in base64 format are in text format, which occupies a small amount of memory, and the converted size ratio is about 1/3, which reduces the consumption of the resource server;
(2) When pictures in base64 format are used in the web page, there is no need to request the server Calling image resources reduces the number of server visits.

Disadvantages
(1) There are more text content in base64 format, which increases the pressure on the database server when stored in the database;
(2) Although there is no need to visit the server to load pictures on the webpage, because the content in base64 format is too much, the speed of loading webpages Will be reduced, which may affect the user experience.

Note: The image of the hospital logo is small, so uploading the hospital logo can be saved in base64 format

6.2. Image base64 tools

Add tool class to common-util module
Add com.atguigu.yygh.common.util.ImageBase64Util class
package com.atguigu.yygh.common.util;

import org.apache.commons.codec.binary.Base64;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class ImageBase64Util {

public static void main(String[] args) { String imageFile= "D:\yygh_work\xh.png";// The picture to be processed System.out.println(getImageString(imageFile)); }


public static String getImageString(String imageFile){ InputStream is = null; try { byte[] data = null; is = new FileInputStream(new File(imageFile)); data = new byte[is.available()]; is.read (data); return new String(Base64.encodeBase64(data)); } catch (Exception e) { e.printStackTrace(); } finally { if (null != is) { try { is.close(); is = null; } catch (Exception e) { e.printStackTrace(); } } } return “”; } }





















6.3. Upload hospital interface correction

When the picture is converted to a base64 string, the string contains a large number of plus signs "+". The server will treat the plus sign as a connector when parsing the data and convert it to a space, so we need to do some special processing.
Modify the ApiController class upload interface

Insert picture description here
@RestController
@RequestMapping("/api/hosp")
public class ApiController {

    @Autowired
    private HospitalService hospitalService;

    @Autowired
    private HospitalSetService hospitalSetService;
    
    //上传医院信息
    @PostMapping("/saveHospital")
    public Result saveHospital(HttpServletRequest request){
        //获取传递过来的医院信息
        Map<String, String[]> requestMap = request.getParameterMap();
        //将Map<String, String[]> 形式转换成Map<String, Object>方便后续使用
        Map<String, Object>  paramMap = HttpRequestHelper.switchMap(requestMap);

        //1、获取医院传递过来的签名,签名进行MD5加密
        String hospSign = (String)paramMap.get("sign");

        //2、根据传递过来的医院编码,查询数据库,查询签名
        String hoscode = (String)paramMap.get("hoscode");
        String signKey = hospitalSetService.getSignKey(hoscode);

        //3、把数据库拆线呢的签名进行加密
        String signKeyMD5 = MD5.encrypt(signKey);

        //3、判断签名是否一致
        if(!hospSign.equals(signKeyMD5)){
            throw new YyghException(ResultCodeEnum.SIGN_ERROR);
        }

        //传输过程中 “+” 转换为了“ ”,因此我们要转换回来
        String logoData = (String)paramMap.get("logoData");
        logoData = logoData.replaceAll(" ","+");
        paramMap.put("logoData",logoData);

        //调用service方法
        hospitalService.save(paramMap);
        return Result.ok();
    }
}

7. Integration test

Refer to "Hospital Interface Simulation System.docx" for interface testing and data upload. No instructions will be given later, it can be used when testing is needed.