一篇关于后台与APP前端网络框架设计

后台用一个Jkid的枚举来定义前端请求数据接口

public enum Jkid {
    UploadYkData("1"),
    DownloadYkData("2"),
    private String value;
    public String getValue() {
        return value;
    }
    Jkid(String value) {
        this.value = value;
    }
    public static Jkid toJkid(String value) {
        for (Jkid jkid : Jkid.values()) {
            if (jkid.getValue().equals(value))
                return jkid;
        }
        return null;
    }
}
工程包目录

DAO持久层   service:业务层代码,实现业务拦截;model:数据模型,实体类,以及映射文件 ; utils:其他工具类

既然用到了spring就不能不提注释了

java用@interface Annotation{}定义一个注解@Annotation,一个注解是一个类。@Override,@Deprecated,@SuppressWarnings为常见的3个注解。

import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
 * 接口注解<br/>
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Component
public @interface JKService {
    /**
     * 枚举接口
     */
    Jkid jkid();
    /**
     * @return 参数对象类型
     */
    Class<?>[] cls() default Object.class;
    /**
     * 编码解码类型
     * @return
     */
    CodecType codecType() default CodecType.PROTOBUF;
    boolean log() default true;

定义一个IAppService.java接口

package com.device.appservice.service;
import com.device.protobuf.response.ServiceResponse;
import com.device.appservice.request.ServiceRequest;
public interface IAppService {
    /**
     * 处理业务逻辑
     * @param request 客户端请求
     * @return 同一返回
     * @throws Exception 将跑出异常 controller
     */
    ServiceResponse doService(ServiceRequest request) throws Exception;
}
这里的ServiceRequest.java

package com.device.appservice.request;
import com.device.appservice.core.CodecType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
 * 客户端请求参数<br/>
 */
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ServiceRequest {
    @NotNull(message = "接口ID不能为空")
    private String jkId;// 接口编号
    private String sign;// 接口签名
    private String time;// 时间戳
    @NotNull(message = "版本号不能为空")
    private String v;// 接口版本
    private String source;// 来源
    private String deviceId; // 用户id
    /**
     * 编码解码方式,客户端可以在消息头里指定,以客户端指定的方式优先
     */
    private CodecType codecType;
    // --------- 以上参数在url中获取
    /**
     * 客户端参数原始数据
     */
    private byte[] bytes;
    /**
     * 客户端参数解析后的对象,从 bytes 解析而来
     */
    private Object paramObj;
    /**
     * 附加对象
     */
    private Map<String, Object> attachments;
    /**
     * 添加一个附件
     * @param key 附加key
     * @param o 附加对象
     */
    public void addAtachment(String key, Object o) {
        if (attachments == null) {
            attachments = new HashMap<>();
        }
        attachments.put(key, o);
    }
    /**
     * 查找一个附加对象
     * @param key 对象key
     * @return 附加的对象
     */
    public Object getAttachment(String key) {
        if (attachments == null) {
            return  null;
        }
        return attachments.get(key);
    }
}
package com.device.protobuf.response;
import com.baidu.bjf.remoting.protobuf.FieldType;
import com.baidu.bjf.remoting.protobuf.annotation.Protobuf;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * 下行,返回给客户端
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ServiceResponse {
    @Protobuf(fieldType = FieldType.STRING, order = 1)
    private String code;//返回码
    @Protobuf(fieldType = FieldType.STRING, order = 2)
    private String msg;//返回信息
    private Object data;//返回数据
    //添加transient关键字标识这个字段对于【Gson】会忽略这个字段,对于【protobuf】不影响
    //未验证对其它JSON是否有同样功能
    @Protobuf(fieldType = FieldType.BYTES, order = 3)
    private transient byte[] bytes;
}
然后BaseServiceImpl.java

package com.device.appservice.service;
import com.device.appservice.codec.IMultiCodec;
import com.device.appservice.core.Code;
import com.device.appservice.core.JKService;
import com.device.appservice.core.Jkid;
import com.device.appservice.core.WebTransException;
import com.device.appservice.domain.manager.ClientParamChecker;
import com.device.appservice.request.ServiceRequest;
import com.device.model.db.TransLine;
import com.device.protobuf.response.ServiceResponse;
import com.device.redis.entity.MemDeviceInfo;
import com.device.redis.service.DeviceMemService;
import com.device.service.TransLineService;
import com.cxy.utils.GsonUtils;
import com.cxy.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.Objects;
import java.util.Observable;
import java.util.UUID;

public abstract class BaseServiceImpl extends Observable implements IAppService {
    protected static final Logger LOGGER = LoggerFactory.getLogger(BaseServiceImpl.class);
    public static final String DEVICE_INFO_KEY = "deviceInfo";
    /**
     * 编码解码器
     */
    @Autowired
    protected IMultiCodec codec;
    @Autowired
    private ClientParamChecker paramChecker;
    @Resource
    TransLineService transLineService;
    @Resource
    @Qualifier("mvcValidator")
    private Validator validator;
    @Autowired
    DeviceMemService deviceMemService;
    public ServiceResponse doService(ServiceRequest serviceRequest) throws Exception {
        long startTime = System.currentTimeMillis();
        serviceRequest = decodeAndCheckParameter(serviceRequest);
        serviceRequest.setDeviceId(serviceRequest.getDeviceId().replaceFirst("^0*", ""));
        ServiceResponse response = getOKServiceResponse();
        //日志入口
        logIn(serviceRequest);
        doServiceBefore(serviceRequest, response);
        TransLine transLine = saveTransLine(serviceRequest);
        response = doBusiness(serviceRequest, response);
        encodeParam(response, serviceRequest);
        doServiceAfter(serviceRequest, response);
        //更新业务流水
        updateTransLine(response, transLine);
        //出口日志
        logOut(serviceRequest, response, startTime, transLine);
        return response;
    }
    public ServiceResponse getOKServiceResponse() {
        ServiceResponse response = new ServiceResponse();
        response.setCode(Code.交易成功.responseCode());
        response.setMsg(Code.交易成功.resonseMsg());
        return response;
    }
    private ServiceRequest decodeAndCheckParameter(ServiceRequest serviceRequest) throws Exception {
        if (isEmptyData(serviceRequest)) {
            return serviceRequest;
        }
        decodeParam(serviceRequest);
        checkParam(serviceRequest.getParamObj());
        paramChecker.checkSign(serviceRequest);
        return serviceRequest;
    }
    private boolean isEmptyData(ServiceRequest request) {
        return Objects.isNull(request) || Objects.isNull(request.getBytes());
    }
    /**
     * 解码,将字节码转换成对象
     *
     * @param serviceRequest
     * @return request 对象
     * @throws ClassNotFoundException
     * @throws IOException
     */
    private ServiceRequest decodeParam(ServiceRequest serviceRequest) throws Exception {
        Class paramRequestClass = getRequestClass();
        if (paramRequestClass.equals(Object.class)) {
            return serviceRequest;
        }
        if (serviceRequest.getBytes() == null || serviceRequest.getBytes().length == 0) {
            return serviceRequest;
        }
        Object paramObj = codec.decode(serviceRequest.getBytes(), paramRequestClass,
                serviceRequest.getCodecType());
        serviceRequest.setParamObj(paramObj);
        return serviceRequest;
    }
    /**
     * 获取参数解析类
     *
     * @return request 类
     * @throws ClassNotFoundException
     */
    protected Class getRequestClass() throws ClassNotFoundException {
        JKService jkservice = AnnotationUtils.findAnnotation(this.getClass(), JKService.class);
        Class<?>[] cls = jkservice.cls();
        for (Class<?> cl : cls) {
            if (cl.getName().contains("Request"))
                return cls[0];
        }
        return cls[0];
    }
    /**
     * 参数有效性检查
     *
     * @param request 客户端请求
     * @throws WebTransException if invalid
     */
    protected void checkParam(Object request) throws WebTransException {
        Errors errors = new BeanPropertyBindingResult(request, request.getClass().getName());
        validator.validate(request, errors);
        if (errors.getErrorCount() == 0) {
            return;
        }
        final StringBuffer stringBuffer = new StringBuffer();
        errors.getFieldErrors().forEach(err -> {
            String str = ":";
            String separator = "|";
            stringBuffer.append(err.getField()).append(str).append(err.getDefaultMessage()).append(separator);
        });
        String errStr = stringBuffer.toString();
        LOGGER.error("参数错误 {}", errStr);
        throw new WebTransException(Code.接口方法参数错误.responseCode(), errStr);
    }
    /**
     * 做业务前准备
     *
     * @param request
     */
    protected void doServiceBefore(ServiceRequest request, ServiceResponse response) throws WebTransException {
        MemDeviceInfo device = deviceMemService.getDeviceInfo(request.getDeviceId());
        if (device == null) {
            throw new WebTransException(Code.设备不存在.responseCode(), Code.设备不存在.resonseMsg() + " : " + request.getDeviceId());
        }
        request.addAtachment(DEVICE_INFO_KEY, device);
    }
    /**
     * 办理业务
     *
     * @param serviceRequest
     * @param serviceResponse
     * @return serviceResponse
     * @throws WebTransException
     */
    protected abstract ServiceResponse doBusiness(ServiceRequest serviceRequest, ServiceResponse serviceResponse) throws WebTransException, IOException;
    /**
     * 做业务前准备
     *
     * @param request
     */
    protected void doServiceAfter(ServiceRequest request, ServiceResponse response) {
    }
    /**
     * 保存业务流水
     *
     * @param request serviceRequest that decoded
     */
    private TransLine saveTransLine(ServiceRequest request) {
        if (isLog()) {
            TransLine transLine = new TransLine();
//            UUID uuid = UUID.randomUUID();
//            transLine.setId(uuid.toString());
            transLine.setJkId(String.valueOf(request.getJkId()));
            transLine.setImei(request.getDeviceId());
            transLine.setReqData(GsonUtils.bean2json(request.getParamObj()));
            transLine.setTransTime(new Date());
            transLineService.save(transLine);
            return transLine;
        }
        return null;
    }
    /**
     * 更新业务流水
     */
    private void updateTransLine(ServiceResponse response, TransLine transLine) {
        if (isLog()) {
            String value = GsonUtils.bean2json(response.getData());
            if (StringUtils.isNotEmptyByTrim(value) && value.length() >= 4000)
                value = value.substring(0, 1000) + "...." + value.substring(value.length() - 1000);
            transLine.setRespData(value);
            transLineService.save(transLine);
        }
    }
    /**
     * 编码参数
     *
     * @param serviceResponse 包含客户端参数类
     * @param serviceRequest
     * @return 同一返回
     * @throws IOException if can not encode
     */
    protected ServiceResponse encodeParam(ServiceResponse serviceResponse, ServiceRequest serviceRequest) throws IOException {
        if (Objects.isNull(serviceResponse.getData())) {
            return serviceResponse;
        }
        byte[] bytes = codec.encode(serviceResponse.getData(), serviceRequest.getCodecType());
        serviceResponse.setBytes(bytes);
        return serviceResponse;
    }
    /**
     * 获取参数对象
     *
     * @param serviceRequest include param
     * @param clazz          param class
     * @param <T>            param type
     * @return param object
     */
    protected <T> T getParam(ServiceRequest serviceRequest, Class<T> clazz) throws WebTransException {
        if (Objects.isNull(serviceRequest.getParamObj())) {
            throw new WebTransException(Code.接口方法参数错误.responseCode(), "没有参数,加入参数");
        }
        return (T) serviceRequest.getParamObj();
    }
    protected <T> T getParam(ServiceRequest serviceRequest) throws WebTransException {
        if (Objects.isNull(serviceRequest.getParamObj())) {
            throw new WebTransException(Code.接口方法参数错误.responseCode(), "没有参数,加入参数");
        }
        return (T) serviceRequest.getParamObj();
    }
    protected boolean isLog() {
        JKService jkservice = AnnotationUtils.findAnnotation(this.getClass(), JKService.class);
        return jkservice.log();
    }
    /**
     * 设置参数对象
     *
     * @param serviceResponse 同一返回
     * @param data            参数对象
     * @return
     */
    protected ServiceResponse setData(ServiceResponse serviceResponse, Object data) {
        serviceResponse.setData(data);
        return serviceResponse;
    }
    public void logIn(ServiceRequest serviceRequest) {
        if (isLog()) {
            LOGGER.info("\n[业务入口] :"
                            + "\n硬件标识 : {}"
                            + "\n服务接口 : {}"
                            + "\n接口名称 : {}"
                            + "\n请求数据 : {}"
                    , serviceRequest.getDeviceId()
                    , serviceRequest.getJkId()
                    , Jkid.toJkid(serviceRequest.getJkId()).name()
                    , GsonUtils.bean2json(serviceRequest.getParamObj()));
        }
    }
    protected void logOut(ServiceRequest serviceRequest, ServiceResponse serviceResponse,
                          long startTime, TransLine transLine) {
        if (isLog()) {
            long ss = System.currentTimeMillis() - startTime;
            String transLineId = (transLine == null ? "" : transLine.getId());
            LOGGER.info(getFormat()
                    , transLineId
                    , serviceRequest.getDeviceId()
                    , serviceResponse.getCode()
                    , serviceResponse.getMsg()
                    , GsonUtils.bean2json(serviceResponse.getData()),
                    ss);
        }
    }
    private String getFormat() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("\n[业务出口] :")
                .append("\n流水号 : {}")
                .append("\n硬件标识 : {}")
                .append("\n返回编码 : {}")
                .append("\n返回信息 : {}")
                .append("\n返回数据 : {}")
                .append("\n服务耗时 : {}");
        return stringBuilder.toString();
    }
}

看一个具体的服务实现

package com.device.appservice.service.impl;
import com.device.appservice.core.*;
import com.device.appservice.request.ServiceRequest;
import com.device.appservice.service.BaseServiceImpl;
import com.device.dao.repo.DeviceVehicleRelRepo;
import com.device.dao.repo.UserTraffinfoRepo;
import com.device.model.db.UserTraffinfo;
import com.device.model.db.Vehicle;
import com.device.protobuf.response.ServiceResponse;
import com.device.protobuf.violation.GetVehicleJszInfo;
import com.device.thirdparty.eagleeye.CheckVehicleService;
import com.device.traffservice.api.TraffService;
import com.cxy.utils.DateUtils;
import com.cxy.utils.GsonUtils;
import com.cxy.utils.StringUtils;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 获取车辆、驾驶证信息
 */
@JKService(jkid = Jkid.GetVehicleJszInfo, cls={GetVehicleJszInfo.Request.class, GetVehicleJszInfo.Response.class}, codecType = CodecType.JSON)
public class GetVehicleAndJszServiceImpl extends BaseServiceImpl{

    @Autowired
    private DeviceVehicleRelRepo deviceVehicleRelRepo;
    @Autowired
    TraffService traffService;

    @Autowired
    UserTraffinfoRepo userTraffinfoRepo;

    @Override
    protected ServiceResponse doBusiness(ServiceRequest serviceRequest, ServiceResponse serviceResponse) throws WebTransException, IOException {
        GetVehicleJszInfo.Response responseData = new GetVehicleJszInfo.Response();

        GetVehicleJszInfo.Request paramObj = (GetVehicleJszInfo.Request)serviceRequest.getParamObj();

        Map<String, String> map = new HashedMap();
        List<UserTraffinfo> userTraffinfoList = userTraffinfoRepo.findByImei(serviceRequest.getDeviceId());

        Vehicle vehicleByImei = deviceVehicleRelRepo.findVehicleByImei(serviceRequest.getDeviceId());

        if(vehicleByImei != null){
            map.put("hphm", vehicleByImei.getHphm());
            if(userTraffinfoList != null && userTraffinfoList.size() > 0){
            UserTraffinfo userTraffinfo = userTraffinfoList.get(0);
            //获取车辆违法笔数
                Integer traffcount = userTraffinfo.getTraffcount();
                if(traffcount != null)
                map.put("traffinfo", traffcount.toString());
            map.put("jszhm", userTraffinfo.getJszhm());
            map.put("jsr", userTraffinfo.getJsr());

            //获取车辆年审到期日
            String yxqz = userTraffinfo.getNsdqr();
            if(StringUtils.isNotEmptyByTrim(yxqz)){
                Date yxqzDate = DateUtils.stringToDate(yxqz, "yyyy-MM-dd HH:mm:ss");
                Date now = new Date();
                long yxqzLong = yxqzDate.getTime();
                long nowLong = now.getTime();
                long days = (yxqzLong -nowLong)/(1000*60*60*24);

                String value = Math.abs(days >= 0 ? (days + 1) : days) + "";
                map.put("nsdqr", value);
            }

            //获取驾驶证清分日期
            String cclzrq = userTraffinfo.getQfrq();
            if(StringUtils.isNotEmptyByTrim(cclzrq)){

                Date today = new Date();

                String qfrq = DateUtils.getQFRQ(cclzrq);
                Date qfrqDate = DateUtils.stringToDate(qfrq, "yyyyMMdd");

                int jlqfDate = (int) ((qfrqDate.getTime() - today.getTime()) / (24 * 60 * 60 * 1000));

                map.put("qfrq", jlqfDate+"");
            }

        }

        //获取车所属单位
        if(paramObj != null){
            CheckVehicleService.CheckVehicleRequest checkVehicleRequest =
                    new CheckVehicleService.CheckVehicleRequest(paramObj.getAreaCode().substring(0, 4) + "00",vehicleByImei.getHphm(), vehicleByImei.getHpzl());
            com.cxy.cxydevice.thirdparty.common.ServiceResponse checkVehicleResponse = CheckVehicleService.getEagleeyeService()
                    .doService(checkVehicleRequest);
            if (checkVehicleResponse != null && checkVehicleResponse instanceof CheckVehicleService.CheckVehicleResponse) {
                CheckVehicleService.CheckVehicleResponse response = (CheckVehicleService.CheckVehicleResponse) checkVehicleResponse;
                if (response.isHasVehicle()) {
                    String orgname = response.getVehicle().getOrgname();
                    map.put("orgname", orgname);
                }
            }
        }

        }

        if(!map.isEmpty()){
            responseData.setVehicleJszInfo(GsonUtils.bean2json(map));
            serviceResponse.setCode(Code.交易成功.responseCode());
            serviceResponse.setMsg(Code.交易成功.resonseMsg());
            serviceResponse.setData(responseData);
        }else{
            serviceResponse.setCode(Code.用户登记的资料不完整.responseCode());
            serviceResponse.setCode(Code.用户登记的资料不完整.resonseMsg());
        }

        return serviceResponse;
    }
}
接着给出DAO与model差不多就完整了

package com.device.dao.repo;

import com.device.model.db.TCxyUserRoadline;
import com.device.model.db.UserTraffinfo;
import com.cxy.e.core.repository.GenericRepository;

import java.util.List;
public interface UserTraffinfoRepo extends GenericRepository<UserTraffinfo, String> {

    List<UserTraffinfo> findByImei(String imei);
}
package com.device.model.db;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

import java.util.Date;


@Entity
@Table(name = "t_cxy_user_traffinfo")
public class UserTraffinfo implements com.cxy.e.core.entity.Entity<String> {

	//columns START
	/**
	 * 用户交罚业务相关数据       db_column: id
	 */
	private java.lang.String id;
	/**
	 * 设备编号       db_column: imei
	 */
	private java.lang.String imei;
	/**
	 * 违法笔数       db_column: traffcount
	 */
	private java.lang.Integer traffcount;
	/**
	 * 年审到期日       db_column: nsdqr
	 */
	private java.lang.String nsdqr;
	/**
	 * 清分日期       db_column: qfrq
	 */
	private java.lang.String qfrq;
	/**
	 * 驾驶人       db_column: jsr
	 */
	private java.lang.String jsr;
	/**
	 * 车牌号       db_column: hphm
	 */
	private java.lang.String hphm;
	/**
	 * 驾驶证号       db_column: jszhm
	 */
	private java.lang.String jszhm;
	/**
	 * 更新时间      db_column: update_time
	 */
	private java.util.Date update_time;
	//columns END


	public UserTraffinfo(){
	}

	public UserTraffinfo(
			java.lang.String id
	){
		this.id = id;
	}



	public void setId(java.lang.String value) {
		this.id = value;
	}

	@Id @GeneratedValue(generator="custom-id")
	@GenericGenerator(name="custom-id", strategy = "uuid")
	@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true, length = 40)
	public java.lang.String getId() {
		return this.id;
	}

	@Column(name = "imei", unique = false, nullable = false, insertable = true, updatable = true, length = 30)
	public java.lang.String getImei() {
		return this.imei;
	}

	public void setImei(java.lang.String value) {
		this.imei = value;
	}

	@Column(name = "traffcount", unique = false, nullable = true, insertable = true, updatable = true, length = 10)
	public java.lang.Integer getTraffcount() {
		return this.traffcount;
	}

	public void setTraffcount(java.lang.Integer value) {
		this.traffcount = value;
	}

	@Column(name = "nsdqr", unique = false, nullable = true, insertable = true, updatable = true, length = 20)
	public java.lang.String getNsdqr() {
		return this.nsdqr;
	}

	public void setNsdqr(java.lang.String value) {
		this.nsdqr = value;
	}

	@Column(name = "qfrq", unique = false, nullable = true, insertable = true, updatable = true, length = 20)
	public java.lang.String getQfrq() {
		return this.qfrq;
	}

	public void setQfrq(java.lang.String value) {
		this.qfrq = value;
	}

	@Column(name = "jsr", unique = false, nullable = true, insertable = true, updatable = true, length = 45)
	public java.lang.String getJsr() {
		return this.jsr;
	}

	public void setJsr(java.lang.String value) {
		this.jsr = value;
	}

	@Column(name = "hphm", unique = false, nullable = true, insertable = true, updatable = true, length = 10)
	public java.lang.String getHphm() {
		return this.hphm;
	}

	public void setHphm(java.lang.String value) {
		this.hphm = value;
	}

	@Column(name = "jszhm", unique = false, nullable = true, insertable = true, updatable = true, length = 20)
	public java.lang.String getJszhm() {
		return this.jszhm;
	}

	public void setJszhm(java.lang.String value) {
		this.jszhm = value;
	}

	@Column(name = "update_time", unique = false, nullable = true, insertable = true, updatable = true, length = 0)
	public Date getUpdate_time() {
		return update_time;
	}

	public void setUpdate_time(Date update_time) {
		this.update_time = update_time;
	}
}

APP端的看下一篇吧




猜你喜欢

转载自blog.csdn.net/ation_work/article/details/70946179