11 changed files with 699 additions and 2 deletions
@ -0,0 +1,11 @@ |
|||
package io.sc.engine.mv; |
|||
|
|||
/** |
|||
* 模型创建类型 |
|||
* @author wangshaoping |
|||
* |
|||
*/ |
|||
public enum ModelType { |
|||
IMPORT_FROM_SCORE_RECORD, //模型从评分记录表中导入
|
|||
MANUAL; //手工创建
|
|||
} |
@ -0,0 +1,102 @@ |
|||
package io.sc.engine.mv.controller.sc; |
|||
|
|||
import java.sql.Connection; |
|||
import java.sql.PreparedStatement; |
|||
import java.sql.ResultSet; |
|||
import java.sql.SQLException; |
|||
|
|||
import io.sc.engine.mv.jpa.entity.GeneralResultHistory; |
|||
import io.sc.engine.mv.jpa.entity.ScKsHistory; |
|||
import io.sc.engine.mv.jpa.entity.id.ScKsHistoryId; |
|||
import io.sc.engine.mv.jpa.repository.GeneralResultHistoryRepository; |
|||
import io.sc.engine.mv.jpa.repository.ScKsHistoryRepository; |
|||
import io.sc.engine.mv.sc.echarts.Coordinates; |
|||
import io.sc.engine.mv.service.sc.ScKsHistoryService; |
|||
import io.sc.engine.mv.vo.ScKsHistoryVo; |
|||
import io.sc.platform.core.util.CollectionUtil; |
|||
import io.sc.platform.mvc.controller.support.RestCrudController; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.dao.DataAccessException; |
|||
import org.springframework.jdbc.core.JdbcTemplate; |
|||
import org.springframework.jdbc.core.PreparedStatementCreator; |
|||
import org.springframework.jdbc.core.ResultSetExtractor; |
|||
import org.springframework.stereotype.Controller; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.servlet.ModelAndView; |
|||
|
|||
@Controller |
|||
@RequestMapping("/mv/sc/ks") |
|||
public class KsWebController extends RestCrudController<ScKsHistoryVo, ScKsHistory, ScKsHistoryId, ScKsHistoryRepository, ScKsHistoryService> { |
|||
//模型验证结果DAO
|
|||
@Autowired private GeneralResultHistoryRepository generalResultHistoryRepository; |
|||
//jdbc 模板
|
|||
@Autowired private JdbcTemplate jdbcTemplate; |
|||
|
|||
/** |
|||
* 查看模型区分能力验证 KS 指标数据UI |
|||
* @param modelId 模型标识 |
|||
* @param validateDate 验证日期 |
|||
* @return UI视图 |
|||
*/ |
|||
@RequestMapping("ksDataView") |
|||
public ModelAndView rocDataView( |
|||
@RequestParam(name="modelId",required=false) String modelId, |
|||
@RequestParam(name="validateDate",required=false) String validateDate |
|||
){ |
|||
ModelAndView mv =new ModelAndView("org/wsp/model/validator/view/sc/ksDataView.html"); |
|||
mv.addObject("removeNavbar", true); |
|||
mv.addObject("modelId", modelId); |
|||
mv.addObject("validateDate", validateDate); |
|||
mv.addObject("distinctModelIdAndNames", CollectionUtil.arrayList2Map(service.getRepository().findDistinctModelIdAndNames())); |
|||
return mv; |
|||
} |
|||
|
|||
/** |
|||
* 获取模型区分能力 KS 曲线的 echarts Options |
|||
* @param modelId 模型标识 |
|||
* @param validateDate 验证日期 |
|||
* @return 模型区分能力 KS 曲线的 echarts Options 的 javascript |
|||
* @throws Exception 违例 |
|||
*/ |
|||
@RequestMapping("ks.js") |
|||
public ModelAndView ks( |
|||
@RequestParam("modelId") String modelId, |
|||
@RequestParam("validateDate") String validateDate |
|||
) throws Exception{ |
|||
ModelAndView mv =new ModelAndView("org/wsp/model/validator/view/sc/echarts/ks.js"); |
|||
GeneralResultHistory resultSummary =generalResultHistoryRepository.findByModelIdAndValidateDate(modelId, validateDate); |
|||
mv.addObject("resultSummary", resultSummary); |
|||
mv.addObject("coordinates",getCoordinates(modelId,validateDate)); |
|||
return mv; |
|||
} |
|||
|
|||
/** |
|||
* 获取 KS 曲线图中 X,Y1,Y2 坐标集 |
|||
* @param modelId 模型标识 |
|||
* @param validateDate 验证日期 |
|||
* @return ROC 曲线图中 X,Y1,Y2 坐标集 |
|||
*/ |
|||
private Coordinates getCoordinates(final String modelId, final String validateDate){ |
|||
return jdbcTemplate.query(new PreparedStatementCreator() { |
|||
@Override |
|||
public PreparedStatement createPreparedStatement(Connection con) throws SQLException { |
|||
String sql ="select FD_SCORE_CUT_OFF_POINT FD_X,FD_Y1,FD_Y2 from MV_SC_KS_HIS where FD_MODEL_ID=? and FD_VALIDATE_DATE=? order by FD_X"; |
|||
PreparedStatement ps =con.prepareStatement(sql); |
|||
ps.setString(1, modelId); |
|||
ps.setString(2, validateDate); |
|||
return ps; |
|||
} |
|||
}, new ResultSetExtractor<Coordinates>() { |
|||
@Override |
|||
public Coordinates extractData(ResultSet rs) throws SQLException, DataAccessException { |
|||
Coordinates coordinates =new Coordinates(); |
|||
while(rs.next()){ |
|||
coordinates.add(rs.getBigDecimal("FD_X"), rs.getBigDecimal("FD_Y1"), rs.getBigDecimal("FD_Y2")); |
|||
} |
|||
coordinates.setScale("y",2); |
|||
return coordinates; |
|||
} |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
io.sc.engine.mv.initializer.ConfigurationInitializer |
@ -0,0 +1,179 @@ |
|||
package io.sc.platform.core.support; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.math.RoundingMode; |
|||
|
|||
public class NumberIterator { |
|||
private BigDecimal from; //初始值
|
|||
private BigDecimal to; //目标值
|
|||
private BigDecimal step; //步长
|
|||
private BigDecimal current; //当前值
|
|||
|
|||
private int scale =2; //精度位数
|
|||
private RoundingMode roundingMode=RoundingMode.HALF_UP; //四舍五入模式
|
|||
|
|||
/** |
|||
* 默认构造函数 |
|||
*/ |
|||
public NumberIterator(){ |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 构造函数(精度为2,采用四舍五入模式) |
|||
* @param from 起始值 |
|||
* @param to 目标值 |
|||
* @param step 步长 |
|||
*/ |
|||
public NumberIterator(String from,String to,String step){ |
|||
this(from,to,step,2,RoundingMode.HALF_UP); |
|||
} |
|||
|
|||
/** |
|||
* 构造函数 |
|||
* @param from 起始值 |
|||
* @param to 目标值 |
|||
* @param step 步长 |
|||
* @param scale 精度 |
|||
* @param roundingMode 四舍五入模式 |
|||
*/ |
|||
public NumberIterator(String from,String to,String step, int scale,RoundingMode roundingMode){ |
|||
this.from =new BigDecimal(from); |
|||
this.current =new BigDecimal(from); |
|||
this.to =new BigDecimal(to); |
|||
this.step =new BigDecimal(step); |
|||
this.scale =scale; |
|||
this.roundingMode =roundingMode; |
|||
} |
|||
|
|||
/** |
|||
* 获取初始值 |
|||
* @return 初始值 |
|||
*/ |
|||
public BigDecimal getFrom() { |
|||
return from; |
|||
} |
|||
|
|||
/** |
|||
* 设置初始值 |
|||
* @param from 初始值 |
|||
*/ |
|||
public void setFrom(BigDecimal from) { |
|||
this.from = from; |
|||
} |
|||
|
|||
/** |
|||
* 获取目标值 |
|||
* @return 目标值 |
|||
*/ |
|||
public BigDecimal getTo() { |
|||
return to; |
|||
} |
|||
|
|||
/** |
|||
* 设置目标值 |
|||
* @param to 目标值 |
|||
*/ |
|||
public void setTo(BigDecimal to) { |
|||
this.to = to; |
|||
} |
|||
|
|||
/** |
|||
* 获取步长 |
|||
* @return 步长 |
|||
*/ |
|||
public BigDecimal getStep() { |
|||
return step; |
|||
} |
|||
|
|||
/** |
|||
* 设置步长 |
|||
* @param step 步长 |
|||
*/ |
|||
public void setStep(BigDecimal step) { |
|||
this.step = step; |
|||
} |
|||
|
|||
/** |
|||
* 获取当前值 |
|||
* @return 当前值 |
|||
*/ |
|||
public BigDecimal getCurrent() { |
|||
return current; |
|||
} |
|||
|
|||
/** |
|||
* 设置当前值 |
|||
* @param current 当前值 |
|||
*/ |
|||
public void setCurrent(BigDecimal current) { |
|||
this.current = current; |
|||
} |
|||
|
|||
/** |
|||
* 获取精度 |
|||
* @return 精度 |
|||
*/ |
|||
public int getScale() { |
|||
return scale; |
|||
} |
|||
|
|||
/** |
|||
* 设置精度 |
|||
* @param scale 精度 |
|||
*/ |
|||
public void setScale(int scale) { |
|||
this.scale = scale; |
|||
} |
|||
|
|||
/** |
|||
* 获取四舍五入模式 |
|||
* @return 四舍五入模式 |
|||
*/ |
|||
public RoundingMode getRoundingMode() { |
|||
return roundingMode; |
|||
} |
|||
|
|||
/** |
|||
* 设置四舍五入模式 |
|||
* @param roundingMode 四舍五入模式 |
|||
*/ |
|||
public void setRoundingMode(RoundingMode roundingMode) { |
|||
this.roundingMode = roundingMode; |
|||
} |
|||
|
|||
/** |
|||
* 获取下一个值 |
|||
* @return 下一个值 |
|||
*/ |
|||
public BigDecimal next(){ |
|||
BigDecimal result =current; |
|||
current =current.add(step); |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 获取是否还有下一个值 |
|||
* @return 是否还有下一个值 |
|||
*/ |
|||
public boolean hasNext(){ |
|||
if(step.doubleValue()>0){ |
|||
return current.compareTo(to)<=0; |
|||
}else{ |
|||
return current.compareTo(to)>=0; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 重置 |
|||
*/ |
|||
public void reset(){ |
|||
current =from; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
return "NumberIterator [from=" + from + ", to=" + to + ", step=" + step + ", current=" + current + ", scale=" |
|||
+ scale + ", roundingMode=" + roundingMode + "]"; |
|||
} |
|||
} |
@ -0,0 +1,5 @@ |
|||
package io.sc.platform.data; |
|||
|
|||
public interface ItemProcessor<S, T> { |
|||
public T process(S item) throws Exception; |
|||
} |
@ -0,0 +1,10 @@ |
|||
package io.sc.platform.data; |
|||
|
|||
import java.io.Closeable; |
|||
import java.io.IOException; |
|||
|
|||
public interface ItemReader<T> extends Closeable { |
|||
public void init() throws IOException; |
|||
public boolean hasNext() throws IOException; |
|||
public T read() throws IOException; |
|||
} |
@ -0,0 +1,10 @@ |
|||
package io.sc.platform.data; |
|||
|
|||
import java.io.Closeable; |
|||
import java.io.IOException; |
|||
import java.util.List; |
|||
|
|||
public interface ItemWriter<T> extends Closeable { |
|||
public void init() throws IOException; |
|||
public void write(List<T> items) throws IOException; |
|||
} |
@ -0,0 +1,87 @@ |
|||
package io.sc.platform.data.job; |
|||
|
|||
import io.sc.platform.data.csv.RecordMapper; |
|||
import io.sc.platform.data.csv.CsvItemProcessor; |
|||
import io.sc.platform.data.csv.CsvItemReader; |
|||
import io.sc.platform.data.csv.CsvItemWriter; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
public class Job { |
|||
private String name; |
|||
private List<JobStep> steps =new ArrayList<>(); |
|||
private boolean async; |
|||
|
|||
public Job(String name){ |
|||
this.name =name; |
|||
} |
|||
|
|||
public Job name(String name){ |
|||
this.name =name; |
|||
return this; |
|||
} |
|||
|
|||
public Job addStep(JobStep step){ |
|||
this.steps.add(step); |
|||
return this; |
|||
} |
|||
|
|||
public Job async(boolean async){ |
|||
this.async =async; |
|||
return this; |
|||
} |
|||
|
|||
public void execute() throws Exception{ |
|||
if(steps!=null && !steps.isEmpty()){ |
|||
for(JobStep step : steps){ |
|||
step.execute(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
|
|||
public List<JobStep> getSteps() { |
|||
return steps; |
|||
} |
|||
|
|||
public void setSteps(List<JobStep> steps) { |
|||
this.steps = steps; |
|||
} |
|||
|
|||
public boolean isAsync() { |
|||
return async; |
|||
} |
|||
|
|||
public void setAsync(boolean async) { |
|||
this.async = async; |
|||
} |
|||
|
|||
public static void main(String[] args) throws Exception { |
|||
RecordMapper mapper =new RecordMapper(); |
|||
mapper.addMapping("CUSTOMER_ID",0); |
|||
mapper.addMapping("SCORE",1); |
|||
mapper.addMapping("LEVEL",2); |
|||
mapper.addMapping("IS_DEFAULT",3); |
|||
CsvItemReader reader =new CsvItemReader(mapper); |
|||
reader.setResourceUrl("classpath:/泰隆银行_信用卡_工薪模型_验证样本.csv"); |
|||
reader.setSkipLines(1); |
|||
reader.setSplitChar(","); |
|||
CsvItemProcessor processor =new CsvItemProcessor(); |
|||
CsvItemWriter writer =new CsvItemWriter(); |
|||
|
|||
JobStep step =new JobStep("step"); |
|||
step.reader(reader); |
|||
step.processor(processor); |
|||
step.writer(writer); |
|||
|
|||
new Job("csv job").addStep(step).execute(); |
|||
} |
|||
} |
@ -0,0 +1,122 @@ |
|||
package io.sc.platform.data.job; |
|||
|
|||
import io.sc.platform.data.ItemProcessor; |
|||
import io.sc.platform.data.ItemReader; |
|||
import io.sc.platform.data.ItemWriter; |
|||
|
|||
import java.io.IOException; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
public class JobStep { |
|||
public static final int DEFAULT_CHUNK =20; |
|||
private String name; |
|||
private int chunk =DEFAULT_CHUNK; |
|||
private ItemReader reader; |
|||
private ItemProcessor processor; |
|||
private ItemWriter writer; |
|||
|
|||
public JobStep(){} |
|||
|
|||
public JobStep(String name){ |
|||
this.name =name; |
|||
} |
|||
|
|||
public JobStep name(String name){ |
|||
this.name =name; |
|||
return this; |
|||
} |
|||
|
|||
public JobStep chunk(int chunk){ |
|||
if(chunk<1){ |
|||
this.chunk =DEFAULT_CHUNK; |
|||
} |
|||
this.chunk =chunk; |
|||
return this; |
|||
} |
|||
|
|||
public JobStep reader(ItemReader reader){ |
|||
this.reader =reader; |
|||
return this; |
|||
} |
|||
|
|||
public JobStep processor(ItemProcessor processor){ |
|||
this.processor =processor; |
|||
return this; |
|||
} |
|||
|
|||
public JobStep writer(ItemWriter writer){ |
|||
this.writer =writer; |
|||
return this; |
|||
} |
|||
|
|||
public void execute() throws Exception { |
|||
if(reader==null){ |
|||
throw new RuntimeException("reader is null"); |
|||
} |
|||
if(processor==null){ |
|||
throw new RuntimeException("processor is null"); |
|||
} |
|||
if(writer==null){ |
|||
throw new RuntimeException("writer is null"); |
|||
} |
|||
|
|||
reader.init(); |
|||
writer.init(); |
|||
long index =0; |
|||
List<Object> list =new ArrayList<>(chunk); |
|||
while(reader.hasNext()){ |
|||
list.add(processor.process(reader.read())); |
|||
if(index%chunk==chunk-1) { |
|||
writer.write(list); |
|||
list.clear(); |
|||
} |
|||
index++; |
|||
} |
|||
if(list.size()>0) { |
|||
writer.write(list); |
|||
} |
|||
reader.close(); |
|||
writer.close(); |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
|
|||
public int getChunk() { |
|||
return chunk; |
|||
} |
|||
|
|||
public void setChunk(int chunk) { |
|||
this.chunk = chunk; |
|||
} |
|||
|
|||
public ItemReader getReader() { |
|||
return reader; |
|||
} |
|||
|
|||
public void setReader(ItemReader reader) { |
|||
this.reader = reader; |
|||
} |
|||
|
|||
public ItemProcessor getProcessor() { |
|||
return processor; |
|||
} |
|||
|
|||
public void setProcessor(ItemProcessor processor) { |
|||
this.processor = processor; |
|||
} |
|||
|
|||
public ItemWriter getWriter() { |
|||
return writer; |
|||
} |
|||
|
|||
public void setWriter(ItemWriter writer) { |
|||
this.writer = writer; |
|||
} |
|||
} |
@ -0,0 +1,170 @@ |
|||
package io.sc.platform.developer.wrapper.springboot; |
|||
|
|||
import io.sc.platform.core.util.StringUtil; |
|||
import org.springframework.boot.actuate.web.mappings.HandlerMethodDescription; |
|||
import org.springframework.boot.actuate.web.mappings.servlet.RequestMappingConditionsDescription.MediaTypeExpressionDescription; |
|||
import org.springframework.boot.actuate.web.mappings.servlet.RequestMappingConditionsDescription.NameValueExpressionDescription; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
public class MappingWrapper { |
|||
private String className; |
|||
private String methodName; |
|||
private String methodDescriptor; |
|||
private String httpMethods; |
|||
private String patterns; |
|||
private String consumes; |
|||
private String produces; |
|||
private String headers; |
|||
private String params; |
|||
|
|||
public MappingWrapper( |
|||
HandlerMethodDescription handler, |
|||
Set<RequestMethod> httpMethods, |
|||
Set<String> patterns, |
|||
List<MediaTypeExpressionDescription> consumes, |
|||
List<MediaTypeExpressionDescription> produces, |
|||
List<NameValueExpressionDescription> headers, |
|||
List<NameValueExpressionDescription> params){ |
|||
this.className =handler.getClassName(); |
|||
this.methodName =handler.getName(); |
|||
this.methodDescriptor =handler.getDescriptor(); |
|||
this.patterns =StringUtil.combine(",",patterns); |
|||
|
|||
if(httpMethods!=null && !httpMethods.isEmpty()){ |
|||
List<String> list =new ArrayList<>(httpMethods.size()); |
|||
for(RequestMethod requestMethod : httpMethods){ |
|||
list.add(requestMethod.toString()); |
|||
} |
|||
this.httpMethods =StringUtil.combine(",",list); |
|||
} |
|||
if(consumes!=null && !consumes.isEmpty()){ |
|||
List<String> list =new ArrayList<>(consumes.size()); |
|||
for(MediaTypeExpressionDescription description : consumes){ |
|||
list.add(formatMediaTypeExpressionDescription(description)); |
|||
} |
|||
this.consumes =StringUtil.combine(",",list); |
|||
} |
|||
if(produces!=null && !produces.isEmpty()){ |
|||
List<String> list =new ArrayList<>(produces.size()); |
|||
for(MediaTypeExpressionDescription description : produces){ |
|||
list.add(formatMediaTypeExpressionDescription(description)); |
|||
} |
|||
this.produces =StringUtil.combine(",",list); |
|||
} |
|||
if(headers!=null && !headers.isEmpty()){ |
|||
List<String> list =new ArrayList<>(headers.size()); |
|||
for(NameValueExpressionDescription description : headers){ |
|||
list.add(formatNameValueExpressionDescription(description)); |
|||
} |
|||
this.headers =StringUtil.combine(",",list); |
|||
} |
|||
if(params!=null && !params.isEmpty()){ |
|||
List<String> list =new ArrayList<>(params.size()); |
|||
for(NameValueExpressionDescription description : params){ |
|||
list.add(formatNameValueExpressionDescription(description)); |
|||
} |
|||
this.params =StringUtil.combine(",",list); |
|||
} |
|||
} |
|||
|
|||
private String formatMediaTypeExpressionDescription(MediaTypeExpressionDescription description){ |
|||
if(description==null){ |
|||
return null; |
|||
} |
|||
if(description.isNegated()){ |
|||
return "-" + description.getMediaType(); |
|||
}else{ |
|||
return "+" + description.getMediaType(); |
|||
} |
|||
} |
|||
|
|||
private String formatNameValueExpressionDescription(NameValueExpressionDescription description){ |
|||
if(description==null){ |
|||
return null; |
|||
} |
|||
if(description.isNegated()){ |
|||
return "-" + description.getName() + "" + description.getValue(); |
|||
}else{ |
|||
return "-" + description.getName() + "" + description.getValue(); |
|||
} |
|||
} |
|||
|
|||
|
|||
public String getClassName() { |
|||
return className; |
|||
} |
|||
|
|||
public void setClassName(String className) { |
|||
this.className = className; |
|||
} |
|||
|
|||
public String getMethodName() { |
|||
return methodName; |
|||
} |
|||
|
|||
public void setMethodName(String methodName) { |
|||
this.methodName = methodName; |
|||
} |
|||
|
|||
public String getMethodDescriptor() { |
|||
return methodDescriptor; |
|||
} |
|||
|
|||
public void setMethodDescriptor(String methodDescriptor) { |
|||
this.methodDescriptor = methodDescriptor; |
|||
} |
|||
|
|||
public String getHttpMethods() { |
|||
return httpMethods; |
|||
} |
|||
|
|||
public void setHttpMethods(String httpMethods) { |
|||
this.httpMethods = httpMethods; |
|||
} |
|||
|
|||
public String getPatterns() { |
|||
return patterns; |
|||
} |
|||
|
|||
public void setPatterns(String patterns) { |
|||
this.patterns = patterns; |
|||
} |
|||
|
|||
public String getConsumes() { |
|||
return consumes; |
|||
} |
|||
|
|||
public void setConsumes(String consumes) { |
|||
this.consumes = consumes; |
|||
} |
|||
|
|||
public String getProduces() { |
|||
return produces; |
|||
} |
|||
|
|||
public void setProduces(String produces) { |
|||
this.produces = produces; |
|||
} |
|||
|
|||
public String getHeaders() { |
|||
return headers; |
|||
} |
|||
|
|||
public void setHeaders(String headers) { |
|||
this.headers = headers; |
|||
} |
|||
|
|||
public String getParams() { |
|||
return params; |
|||
} |
|||
|
|||
public void setParams(String params) { |
|||
this.params = params; |
|||
} |
|||
|
|||
|
|||
} |
Loading…
Reference in new issue