spring boot项目实战之理财系统

 

项目完整代码下载地址: https://gitee.com/chuzhuyong/financial-project/tree/master

 

一、项目准备

模块化开发的好处

  高内聚,低耦合

  并行开发,提高开发的效率

如何划分?

  业务层次

  功能划分

  重复使用

spring boot项目实战之理财系统

 

 

 (一)、工程创建

构建工具:gradle

(1)下载网址:https://gradle.org/

spring boot项目实战之理财系统

(2)系统环境变量配置

 spring boot项目实战之理财系统

 

spring boot项目实战之理财系统

 

 

(3)使用gradle -v命令查看配置是否成功

 spring boot项目实战之理财系统

 

 

 

使用IDEA创建项目流程

 spring boot项目实战之理财系统

 

 

     spring boot项目实战之理财系统

 

    spring boot项目实战之理财系统

 

创建模块

    spring boot项目实战之理财系统

 

 

(二)、数据库设计

管理端                     

             产品表

spring boot项目实战之理财系统

销售端:

                      订单表

 

spring boot项目实战之理财系统

 

(三)、创建产品表

create table product(

id VARCHAR(50) not null comment '产品编号',

name VARCHAR(50) not null comment '产品名称',

threshold_amount DECIMAL(15,3) not null comment '起步金额',

step_amount DECIMAL(15,3) not null comment '投资步长',

lock_term SMALLINT not null comment '锁定期',

reward_rate DECIMAL(15,3) not null comment '收益率,0-100 百分比值',

status VARCHAR(20) not null comment '状态,AUDINTING:审核中,IN_SELL:销售 中,LOCKED:暂停销售,FINISHED:已结束',

memo VARCHAR(200) comment '备注',

create_at datetime comment '创建时间',

create_user VARCHAR(20) comment '创建者',

update_at datetime comment '更新时间',

update_user VARCHAR(20) comment '更新者',

PRIMARY KEY(id)

)ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

  spring boot项目实战之理财系统

 

 

  

(四)、创建订单表

create table order_t(

order_id VARCHAR(50) not null comment '订单编号',

chan_id VARCHAR(50) not null comment '渠道编号',

product_id VARCHAR(50) not null comment '产品编号',

chan_user_id VARCHAR(50) not null comment '渠道用户编号',

order_type VARCHAR(50) not null comment '类型,APPLY:申购,REDEEM:赎回',

order_status VARCHAR(50) not null comment '状态,INIT:初始化,PROCESS:处理 中,SUCCESS:成功,FAIL:失败',

outer_order_id VARCHAR(50) not null comment '外部订单编号',

amount DECIMAL(15,3) not null comment '金额',

memo VARCHAR(200) comment '备注',

create_at datetime comment '创建时间',

update_at datetime comment '更新时间',

PRIMARY KEY(order_id)

)ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

spring boot项目实战之理财系统

 

 

(五)、Entity模块

Product

package com.uos.entity;

import java.math.BigDecimal;
import java.util.Date;

/**
 * 产品
 */
@Entity
public class Product {
    @Id
    private String id;
    private String name;
    private String status;
    //起投金额
    private BigDecimal threshouldAmount;
    //投资步长
    private BigDecimal stepAmount;
    //锁定期
    private Integer lockTerm;
    //收益率
    private BigDecimal rewardRate;
    private String memo;
    private Date createAt;
    private Date updateAt;
    private String createUser;
    private String updateUser;

    @Override
    public String toString() {
        return "Order{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", status='" + status + '\'' +
                ", threshouldAmount=" + threshouldAmount +
                ", stepAmount=" + stepAmount +
                ", lockTerm=" + lockTerm +
                ", rewardRate=" + rewardRate +
                ", memo='" + memo + '\'' +
                ", createAt=" + createAt +
                ", updateAt=" + updateAt +
                ", createUser='" + createUser + '\'' +
                ", updateUser='" + updateUser + '\'' +
                '}';
    }


    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public BigDecimal getThreshouldAmount() {
        return threshouldAmount;
    }

    public void setThreshouldAmount(BigDecimal threshouldAmount) {
        this.threshouldAmount = threshouldAmount;
    }

    public BigDecimal getStepAmount() {
        return stepAmount;
    }

    public void setStepAmount(BigDecimal stepAmount) {
        this.stepAmount = stepAmount;
    }

    public Integer getLockTerm() {
        return lockTerm;
    }

    public void setLockTerm(Integer lockTerm) {
        this.lockTerm = lockTerm;
    }

    public BigDecimal getRewardRate() {
        return rewardRate;
    }

    public void setRewardRate(BigDecimal rewardRate) {
        this.rewardRate = rewardRate;
    }

    public String getMemo() {
        return memo;
    }

    public void setMemo(String memo) {
        this.memo = memo;
    }

    public Date getCreateAt() {
        return createAt;
    }

    public void setCreateAt(Date createAt) {
        this.createAt = createAt;
    }

    public Date getUpdateAt() {
        return updateAt;
    }

    public void setUpdateAt(Date updateAt) {
        this.updateAt = updateAt;
    }

    public String getCreateUser() {
        return createUser;
    }

    public void setCreateUser(String createUser) {
        this.createUser = createUser;
    }

    public String getUpdateUser() {
        return updateUser;
    }

    public void setUpdateUser(String updateUser) {
        this.updateUser = updateUser;
    }
}

 

Order类

package com.uos.entity;

import java.math.BigDecimal;
import java.util.Date;

/**
 * 订单
 */
@Entity(name = "order_t")
public class Order {
    @Id
    private String orderId;
    //渠道id
    private String chanId;
    private String chanUserId;
    private String orderType;
    private String productId;
    private BigDecimal amount;
    private String outerOrderId;
    private String orderStatus;
    private String memo;
    private Date createAt;
    private Date updateAt;

    @Override
    public String toString() {
        return "Order{" +
                "orderId='" + orderId + '\'' +
                ", chanId='" + chanId + '\'' +
                ", chanUserId='" + chanUserId + '\'' +
                ", orderType='" + orderType + '\'' +
                ", productId='" + productId + '\'' +
                ", amount=" + amount +
                ", outerOrderId='" + outerOrderId + '\'' +
                ", orderStatus='" + orderStatus + '\'' +
                ", memo='" + memo + '\'' +
                ", createAt=" + createAt +
                ", updateAt=" + updateAt +
                '}';
    }

    public String getOrderId() {
        return orderId;
    }
    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
    public String getChanId() {
        return chanId;
    }
    public void setChanId(String chanId) {
        this.chanId = chanId;
    }
    public String getChanUserId() {
        return chanUserId;
    }
    public void setChanUserId(String chanUserId) {
        this.chanUserId = chanUserId;
    }

    public String getOrderType() {
        return orderType;
    }
    public void setOrderType(String orderType) {
        this.orderType = orderType;
    }
    public String getProductId() {
        return productId;
    }
    public void setProductId(String productId) {
        this.productId = productId;
    }
    public BigDecimal getAmount() {
        return amount;
    }
    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }
    public String getOuterOrderId() {
        return outerOrderId;
    }
    public void setOuterOrderId(String outerOrderId) {
        this.outerOrderId = outerOrderId;
    }
    public String getOrderStatus() {
        return orderStatus;
    }
    public void setOrderStatus(String orderStatus) {
        this.orderStatus = orderStatus;
    }
    public String getMemo() {
        return memo;
    }
    public void setMemo(String memo) {
        this.memo = memo;
    }

    public Date getCreateAt() {
        return createAt;
    }

    public void setCreateAt(Date createAt) {
        this.createAt = createAt;
    }

    public Date getUpdateAt() {
        return updateAt;
    }
    public void setUpdateAt(Date updateAt) {
        this.updateAt = updateAt;
    }
}

 

二、管理端

spring boot项目实战之理财系统

 

(一) 、添加产品

1、管理端启动类

package com.uos.manager;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 管理端启动类
 */
@SpringBootApplication
public class ManagerApp {
    public static void main(String[] args) {
        SpringApplication.run(ManagerApp.class);
    }
}

2、数据库的连接配置application.yml

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/manager?user=root&password=123456&useUnicode=true&characterEncoding=utf-8
  jpa:
    show-sql: true
server:
  context-path: /manager
  port: 8081

3、ProductRepository接口

package com.uos.manager.repositories;

import com.uos.entity.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;


/**
 * 产品管理
 */
public interface ProductRepository extends JpaRepository<Product,String>,JpaSpecificationExecutor<Product> {

}

4、ProductService产品服务类

package com.uos.manager.service;

import com.uos.entity.Product;
import com.uos.entity.enums.ProductStatus;
import com.uos.manager.repositories.ProductRepository;
import org.slf4j.Logger;

import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Date;


/*
    产品服务类
 */
@Service
public class ProductService {
    private static Logger LOG = (Logger) LoggerFactory.getLogger(ProductService.class);

    @Autowired
    private ProductRepository repository;

    public Product addProduct(Product product){
        //打印日志信息
        LOG.debug("创建产品,参数:{}",product);
        //数据校验
        checkProduct(product);
        //设置默认值
        setDefault(product);
        //保存值
        Product result = repository.save(product);

        LOG.debug("创建产品,结果:{}",result);
        return result;
    }
    /*
    设置默认值:
        创建时间、更新时间、投资步长、锁定期
     */
    private void setDefault(Product product) {
        if (product.getCreateAt() == null) {
            product.setCreateAt(new Date());
        }
        if (product.getUpdateAt() == null) {
            product.setUpdateAt(new Date());
        }
        if (product.getStepAmount() == null) {
            product.setStepAmount(BigDecimal.ZERO);
        }
        if (product.getLockTerm() == null) {
            product.setLockTerm(0);
        }
        if (product.getStatus() == null) {
            product.setStatus(ProductStatus.AUDITING.name());
        }
    }

    /*
        产品数据的校验:
        1.非空数据
        2.收益率在0-30%以内
        3.投资步长需要为整数
     */
    private void checkProduct(Product product) {
        Assert.notNull(product.getId(), "编号不可为空");
        //其他非空校验

        Assert.isTrue(BigDecimal.ZERO.compareTo(product.getRewardRate()) < 0 && BigDecimal.valueOf(30).compareTo(product.getRewardRate()) >= 0, "收益率范围错误");

        Assert.isTrue(BigDecimal.valueOf(product.getStepAmount().longValue()).compareTo(product.getStepAmount()) == 0, "投资步长需为整数");


    }
}

5、ProductController产品控制类

package com.uos.manager.controller;

import com.uos.entity.Product;
import com.uos.manager.service.ProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * 产品
 */
@RestController
@RequestMapping("/products")
public class ProductController {
    private static Logger LOG = (Logger) LoggerFactory.getLogger(ProductService.class);
    @Autowired
    private ProductService service;
    @RequestMapping(value = "",method = RequestMethod.POST)
    public Product addProduct(@RequestBody Product product){
        LOG.info("创建产品,参数:{}",product);
        Product result = service.addProduct(product);
        LOG.info("创建产品,结果:{}",result);
        return result;
    }

}

(二)查询产品

1、查询单个产品

 

ProductService中添加

/**
 * 查询单个产品
 */
public Product findOne(String id){
    Assert.notNull(id,"需要产品编号参数");
    LOG.debug("查询单个产品,id={}",id);
    Product product = repository.findOne(id);
    LOG.debug("查询单个产品,结果={}",product);
    return product;
}

ProductController中添加

/**
 * 查询单个产品
 */
@RequestMapping(value = "/{id}",method = RequestMethod.GET )
public Product findOne(@PathVariable String id){
    LOG.info("查询单个产品,id={}",id);
    Product product = service.findOne(id);
    LOG.info("查询单个产品,结果={}",product);
    return product;
}

2、分页查询

ProductService中添加

/**
 * 分页查询
 */
public Page<Product> query(List<String> idList,
                           BigDecimal minRewardRate, BigDecimal maxRewardRate,
                           List<String> statusList,
                           Pageable pageable){
    LOG.debug("查询产品,idList={},minRewardRate={},maxRewardRate={},statusList={},pageable={}",idList,minRewardRate,maxRewardRate,statusList,pageable);

    Specification<Product> specification = new Specification<Product>() {
        @Override
        public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            //获取相关的列
            Expression<String> idCol = root.get("id");
            Expression<BigDecimal> rewardRateCol = root.get("rewardRate");
            Expression<String> statusCol = root.get("status");
            //定义断言列表,用来生成断言
            List<Predicate> predicates = new ArrayList<>();
            //判断产品编号的情况
            if (idList != null && idList.size() > 0){
                predicates.add(idCol.in(idList));
            }
            if (BigDecimal.ZERO.compareTo(minRewardRate) < 0){
                predicates.add(cb.ge(rewardRateCol,minRewardRate));
            }
            if (BigDecimal.ZERO.compareTo(minRewardRate) < 0){
                predicates.add(cb.le(rewardRateCol,maxRewardRate));
            }
            //判断产品状态的情况
            if (statusList != null && statusList.size() > 0){
                predicates.add(statusCol.in(statusList));
            }
            query.where(predicates.toArray(new Predicate[0]));
            return null;
        }
    };
    Page<Product> page = repository.findAll(specification,pageable);
    LOG.debug("查询产品,结果={}",page);
    return page;
}

ProductController中添加

/**
 * 分页查询
 */
@RequestMapping(value = "",method = RequestMethod.GET)
public Page<Product> query(String ids, BigDecimal minRewardRate,BigDecimal maxRewardRate,
                           String status,@RequestParam(defaultValue = "0") int pageNum,@RequestParam(defaultValue = "10") int pageSize){
    LOG.info("查询产品,ids={},minRewardRate={},maxRewardRate={},status,pageNum={},pageSize={}");
    List<String> idList = null,statusList = null;
    //判断产品编号
    if (!StringUtils.isEmpty(ids)){
        idList = Arrays.asList(ids.split(","));
    }
    //判断产品状态
    if (!StringUtils.isEmpty(status)){
        statusList = Arrays.asList(status.split(","));
    }
    Pageable pageable = new PageRequest(pageNum,pageSize);
    Page<Product> page = service.query(idList,minRewardRate,maxRewardRate,statusList,pageable);
    LOG.info("查询产品,结果={}",page);
    return page;
}

在管理端启动类上添加@EntityScan(basePackages = {"com.uos.entity"})

 

)、统一错误处理

  用户友好的错误说明

  统一处理,简化业务代码

  异常标准化

 

自定义格式化时间,在manager模块下的application.yml中添加

spring boot项目实战之理财系统

 

 

 自定义错误页面

spring boot项目实战之理财系统

定义MyErrorController类

package com.uos.manager.error;

import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.web.servlet.error.ErrorAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * 自定义错误处理controller
 */
public class MyErrorController extends BasicErrorController {
    public MyErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
        super(errorAttributes, errorProperties, errorViewResolvers);
    }

    @Override
    protected Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
        Map<String, Object> attrs = super.getErrorAttributes(request, includeStackTrace);
    //去除无关的属性
        attrs.remove("timestamp");
        attrs.remove("status");
        attrs.remove("error");
        attrs.remove("exception");
        attrs.remove("path");
        return attrs;
    }
}

定义ErrorConfiguration类        错误处理相关配置

package com.uos.manager.error;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.*;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * 错误处理相关配置
 */
@Configuration
public class ErrorConfiguration {
    @Bean
    public MyErrorController basicErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties,
                                                  ObjectProvider<List<ErrorViewResolver>> errorViewResolversProvider) {
        return new MyErrorController(errorAttributes, serverProperties.getError(),
                errorViewResolversProvider.getIfAvailable());
    }
}

定义ErrorEnum类  错误种类

package com.uos.manager.error;

/**
 * 错误种类
 */
public enum  ErrorEnum {
    ID_NOT_NULL("F001","编号不能为空",false),
    UNKNOWN("999","未知异常",false);
    private String code;
    private String message;
    private boolean canRetry;

    ErrorEnum(String code, String message, boolean canRetry) {
        this.code = code;
        this.message = message;
        this.canRetry = canRetry;
    }
    //通过编号获取异常
    public static ErrorEnum getByCode(String code){
        for (ErrorEnum errorEnum : ErrorEnum.values()) {
            if (errorEnum.code.equals(code)){
                return errorEnum;
            }
        }
        return UNKNOWN;
    }

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public boolean isCanRetry() {
        return canRetry;
    }
}

MyErrorController中添加相关属性

//获取错误种类
ErrorEnum errorEnum = ErrorEnum.getByCode(errorCode);
//添加相关属性
attrs.put("message",errorEnum.getMessage());
attrs.put("code",errorEnum.getCode());
attrs.put("canRetry",errorEnum.isCanRetry());

新建ErrorControllerAdvice

 

package com.uos.manager.error;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

/**
 * 统一错误处理
 */

@ControllerAdvice(basePackages = {"com.uos.manager.controller"})
public class ErrorControllerAdvice {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseEntity handleException(Exception e){
        Map<String, Object> attrs = new HashMap<>();
        String errorCode = e.getMessage();
        ErrorEnum errorEnum = ErrorEnum.getByCode(errorCode);
        //添加相关属性
        attrs.put("message",errorEnum.getMessage());
        attrs.put("code",errorEnum.getCode());
        attrs.put("canRetry",errorEnum.isCanRetry());
        attrs.put("type","advice");
        return new ResponseEntity(attrs, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

 

说明:ControllerAdvice是Controller的增强

 

 (四)、自动化测试

采用功能测试,使用JUnit框架

util下创建JsonUtil类

 

package com.uos.util;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.DateFormat;

public class JsonUtil {

    private static final Logger LOG = LoggerFactory.getLogger(JsonUtil.class);
    private final static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.enable(SerializationFeature.WRITE_NULL_MAP_VALUES);
        mapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
    // 属性可见度只打印public
    //mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
    }

    public static void setDateFormat(DateFormat dateFormat) {
        mapper.setDateFormat(dateFormat);
    }

    /**
     * 把Java对象转为JSON字符串
     *
     * @param obj the object need to transfer into json string.
     * @return json string.
     */
    public static String toJson(Object obj) {
        try {
            return mapper.writeValueAsString(obj);
        } catch (IOException e) {
            LOG.error("to json exception.", e);
            throw new JSONException("把对象转换为JSON时出错了", e);
        }
    }
}

final class JSONException extends RuntimeException {
    public JSONException(final String message) {
        super(message);
    }

    public JSONException(final String message, final Throwable cause) {
        super(message, cause);
    }
}

 

在util下创建创建RestUtil类

package com.uos.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.Map;


public class RestUtil {

    static Logger log = LoggerFactory.getLogger(RestUtil.class);

    /**
     * 发送post 请求
     *
     * @param restTemplate
     * @param url
     * @param param
     * @param responseType
     * @param <T>
     * @return
     */
    public static <T> T postJSON(RestTemplate restTemplate, String url, Object param, Class<T> responseType) {
        HttpEntity<String> formEntity = makePostJSONEntiry(param);
        T result = restTemplate.postForObject(url, formEntity, responseType);
        log.info("rest-post-json 响应信息:{}", JsonUtil.toJson(result));
        return result;
    }

    /**
     * 生成json形式的请求头
     *
     * @param param
     * @return
     */
    public static HttpEntity<String> makePostJSONEntiry(Object param) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
        HttpEntity<String> formEntity = new HttpEntity<String>(
                JsonUtil.toJson(param), headers);
        log.info("rest-post-json-请求参数:{}", formEntity.toString());
        return formEntity;
    }


    public static HttpEntity<String> makePostTextEntiry(Map<String, ? extends Object> param) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
        HttpEntity<String> formEntity = new HttpEntity<String>(
                makeGetParamContent(param), headers);
        log.info("rest-post-text-请求参数:{}", formEntity.toString());
        return formEntity;
    }


    /**
     * 生成Get请求内容
     *
     * @param param
     * @param excluedes
     * @return
     */
    public static String makeGetParamContent(Map<String, ? extends Object> param, String... excluedes) {
        StringBuilder content = new StringBuilder();
        List<String> excludeKeys = Arrays.asList(excluedes);
        param.forEach((key, v) -> {
            content.append(key).append("=").append(v).append("&");
        });
        if (content.length() > 0) {
            content.deleteCharAt(content.length() - 1);
        }
        return content.toString();
    }
}

编写ProductControllerTest类

测试添加产品

 

package com.uos.manager.controller;

import com.uos.entity.Product;
import com.uos.entity.enums.ProductStatus;
import com.uos.util.RestUtil;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.Assert;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ProductControllerTest { private static RestTemplate rest = new RestTemplate(); @Value("http://localhost:${local.server.port}/manager") private String baseUrl; //测试用例 //正常产品数据 private static List<Product> normals = new ArrayList<>(); //异常产品数据 private static List<Product> exceptions = new ArrayList<>(); @BeforeClass public static void init(){ Product p1 = new Product("T001", "灵活宝1号", ProductStatus.AUDITING.name(), BigDecimal.valueOf(10), BigDecimal.valueOf(1), BigDecimal.valueOf(3.42)); Product p2 = new Product("T002", "活期盈-金色人生", ProductStatus.AUDITING.name(), BigDecimal.valueOf(10), BigDecimal.valueOf(0), BigDecimal.valueOf(3.28)); Product p3 = new Product("T003", "朝朝盈-聚财", ProductStatus.AUDITING.name(), BigDecimal.valueOf(100), BigDecimal.valueOf(10), BigDecimal.valueOf(3.86)); normals.add(p1); normals.add(p2); normals.add(p3); Product e1 = new Product(null, "编号不可为空", ProductStatus.AUDITING.name(), BigDecimal.valueOf(10), BigDecimal.valueOf(1), BigDecimal.valueOf(2.34)); Product e2 = new Product("E002", "收益率范围错误", ProductStatus.AUDITING.name(), BigDecimal.ZERO, BigDecimal.valueOf(1), BigDecimal.valueOf(31)); Product e3 = new Product("E003", "投资步长需为整数", ProductStatus.AUDITING.name(), BigDecimal.ZERO, BigDecimal.valueOf(1.01), BigDecimal.valueOf(3.44)); exceptions.add(e1); exceptions.add(e2); exceptions.add(e3); ResponseErrorHandler errorHandler = new ResponseErrorHandler() { @Override public boolean hasError(ClientHttpResponse response) throws IOException { return false; } @Override public void handleError(ClientHttpResponse response) throws IOException { } }; rest.setErrorHandler(errorHandler); } @Test public void create(){ normals.forEach(product -> { Product result = RestUtil.postJSON(rest,baseUrl+"/products",product,Product.class); Assert.notNull(result.getCreateAt(),"创建失败"); } ); } @Test public void createException(){ exceptions.forEach(product -> { Map<String,String> result = RestUtil.postJSON(rest,baseUrl+"/products",product, HashMap.class); Assert.isTrue(result.get("message").equals(product.getName()), "插入成功"); } ); }
   }

 

  @Test
    public void findOne() {
        normals.forEach(product -> {
            Product result = rest.getForObject(baseUrl + "/products/" + product.getId(), Product.class);
            Assert.isTrue(result.getId().equals(product.getId()), "查询失败");
        });
        exceptions.forEach(product -> {
            Product result = rest.getForObject(baseUrl + "/products/" + product.getId(), Product.class);
            Assert.isNull(result, "查询失败");
        });
    }

 

数据库结果

 spring boot项目实战之理财系统

 

spring boot项目实战之理财系统

 

 spring boot项目实战之理财系统

 

 spring boot项目实战之理财系统

 

 spring boot项目实战之理财系统

 

 spring boot项目实战之理财系统

 

 spring boot项目实战之理财系统

 

 spring boot项目实战之理财系统

 spring boot项目实战之理财系统spring boot项目实战之理财系统

 

 

 

 1 package com.uos.swagger;
 2 
 3 import org.springframework.boot.context.properties.ConfigurationProperties;
 4 import org.springframework.stereotype.Component;
 5 
 6 /**
 7  * swagger配置信息
 8  */
 9 @Component
10 @ConfigurationProperties(prefix = "swagger")
11 public class SwaggerInfo {
12     private String groupName = "controller";
13     private String basePackage;
14     private String antPath;
15     private String title = "HTTP API";
16     private String description = "管理端接口";
17     private String license = "Apache License Version 2.0";
18 
19     public String getGroupName() {
20         return groupName;
21     }
22 
23     public void setGroupName(String groupName) {
24         this.groupName = groupName;
25     }
26 
27     public String getBasePackage() {
28         return basePackage;
29     }
30 
31     public void setBasePackage(String basePackage) {
32         this.basePackage = basePackage;
33     }
34 
35     public String getAntPath() {
36         return antPath;
37     }
38 
39     public void setAntPath(String antPath) {
40         this.antPath = antPath;
41     }
42 
43     public String getTitle() {
44         return title;
45     }
46 
47     public void setTitle(String title) {
48         this.title = title;
49     }
50 
51     public String getDescription() {
52         return description;
53     }
54 
55     public void setDescription(String description) {
56         this.description = description;
57     }
58 
59     public String getLicense() {
60         return license;
61     }
62 
63     public void setLicense(String license) {
64         this.license = license;
65     }
66 }
SwaggerInfo

相关文章: