Merge remote-tracking branch 'origin/dev' into dev
commit
f2b938e668
|
@ -26,7 +26,7 @@ log
|
|||
/log/
|
||||
.DS_Store
|
||||
/src/main/resources/WEB-INF/prop/weaver.properties
|
||||
/lib/classbean
|
||||
|
||||
/file/
|
||||
/src/test/resources/application.properties
|
||||
/src/test/resources/application.xml
|
||||
|
@ -36,7 +36,7 @@ DirectoryV2.xml
|
|||
/lib/classbeanLib/ecology-dev-lib.jar
|
||||
/lib/classbeanLib/web-inf-class-lib.jar
|
||||
/lib/weaverLib/
|
||||
/lib/jitulib/
|
||||
|
||||
*.groovy
|
||||
*.log
|
||||
*.iml
|
||||
|
@ -47,5 +47,8 @@ src/test/resources/font
|
|||
src/main/resources/WEB-INF/vm/outFile
|
||||
target/
|
||||
*.back
|
||||
src/main/aiyh_old_src/
|
||||
src/main/jitu_src/
|
||||
# 老项目代码
|
||||
#/lib/jitulib/
|
||||
#/lib/classbean
|
||||
#src/main/youhong_ai_old_src/
|
||||
#src/main/youhong_ai_jitu_src/
|
|
@ -1,9 +1,9 @@
|
|||
window.Utils = {
|
||||
class CusUtils {
|
||||
/**
|
||||
* @author youhong.ai
|
||||
* @desc 发起请求
|
||||
*/
|
||||
request: function (url, type = "GET", data, isAsync = true, success = () => {
|
||||
request(url, type = "GET", data, isAsync = true, success = () => {
|
||||
}, error = () => {
|
||||
}, complete = () => {
|
||||
}, contentType = 'application/json', beforeSend = () => {
|
||||
|
@ -24,13 +24,13 @@ window.Utils = {
|
|||
options.data = JSON.stringify(data)
|
||||
}
|
||||
return $.ajax(options)
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @author youhong.ai
|
||||
* @desc 发起请求
|
||||
*/
|
||||
api: function (requestOptions = {
|
||||
api(requestOptions = {
|
||||
url: "",
|
||||
type: "GET",
|
||||
data: "",
|
||||
|
@ -61,13 +61,13 @@ window.Utils = {
|
|||
}
|
||||
}, requestOptions)
|
||||
return $.ajax(options)
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @author youhong.ai
|
||||
* @desc 获取react组件实例
|
||||
*/
|
||||
findReact: function (dom, traverseUp = 0) {
|
||||
findReact(dom, traverseUp = 0) {
|
||||
const key = Object.keys(dom).find(key => {
|
||||
return key.startsWith("__reactFiber$") // react 17+
|
||||
|| key.startsWith("__reactInternalInstance$")
|
||||
|
@ -96,7 +96,7 @@ window.Utils = {
|
|||
compFiber = GetCompFiber(compFiber);
|
||||
}
|
||||
return compFiber.stateNode;
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -104,7 +104,7 @@ window.Utils = {
|
|||
* @param fieldName 字段名称
|
||||
* @returns {*|string}
|
||||
*/
|
||||
convertNameToIdUtil: function (fieldName) {
|
||||
convertNameToIdUtil(fieldName) {
|
||||
let fieldIds = [];
|
||||
if (fieldName instanceof Array) {
|
||||
fieldName.forEach(item => {
|
||||
|
@ -113,19 +113,32 @@ window.Utils = {
|
|||
return fieldIds.join(',')
|
||||
}
|
||||
return Utils.convertNameObjToId(fieldName)
|
||||
},
|
||||
}
|
||||
|
||||
getQueryString(name) {
|
||||
let reg = new RegExp("(^|&|\/?)" + name + "=([^&]*)(&|$)", "i");
|
||||
let searchStr = window.location.href
|
||||
if (searchStr.startsWith('&')) {
|
||||
searchStr = searchStr.substr(1)
|
||||
}
|
||||
let search = searchStr.match(reg)
|
||||
if (search != null) {
|
||||
return unescape(search[2]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字段名称转为字段id
|
||||
* @param fieldObj 字段名称对象 {string|object}
|
||||
* @returns {*}
|
||||
*/
|
||||
convertNameObjToId: function (fieldObj = {fieldName: '', table: 'main'}) {
|
||||
convertNameObjToId(fieldObj = {fieldName: '', table: 'main'}) {
|
||||
if (typeof fieldObj === 'object') {
|
||||
return WfForm.convertFieldNameToId(fieldObj.fieldName, fieldObj.table)
|
||||
}
|
||||
return WfForm.convertFieldNameToId(fieldObj)
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字段名称查询字段值
|
||||
|
@ -133,17 +146,18 @@ window.Utils = {
|
|||
* @param rowIndex 明细行下表(明细获取才传递)
|
||||
* @returns {*} 字段值
|
||||
*/
|
||||
getFiledValueByName: function (fieldName, rowIndex) {
|
||||
getFiledValueByName(fieldName, rowIndex) {
|
||||
return WfForm.getFieldValue(Utils.convertNameObjToId(fieldName) + (rowIndex ? '_' + rowIndex : ''))
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过字段名称修改字段值
|
||||
* @param fieldName 字段名称
|
||||
* @param value 值
|
||||
*/
|
||||
changeFieldValueByName: function (fieldName, value) {
|
||||
changeFieldValueByName(fieldName, value) {
|
||||
WfForm.changeFieldValue(Utils.convertNameObjToId(fieldName), {value})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.Utils = new CusUtils()
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
const ecodeSDK = {}
|
||||
ecodeSDK.setCom = (id, name, Com) => {
|
||||
}
|
||||
ecodeSDK.imp = (obj) => {
|
||||
}
|
||||
ecodeSDK.exp = (obj) => {
|
||||
}
|
||||
const WfForm = {
|
||||
isMobile: () => {
|
||||
// true表示是eMobile、微信、钉钉等移动终端,false代表PC端
|
||||
|
|
|
@ -25,20 +25,39 @@ const detail3TaxField = WfForm.convertFieldNameToId("ddhsje", "detail_3");
|
|||
// 明细3以收票金额
|
||||
const detail3YspField = WfForm.convertFieldNameToId("yspje","detail_3");
|
||||
|
||||
const detail3ApplyMoneyField = WfForm.convertFieldNameToId("bcfkje", "detail_3");
|
||||
const detail3CgId = WfForm.convertFieldNameToId("cgddzbid", "detail_3");
|
||||
const detail3Bl = WfForm.convertFieldNameToId('bcfkbl', "detail_3");
|
||||
let detailBlMap = new Map();
|
||||
const detail1Bl = WfForm.convertFieldNameToId('bcljfkbl', "detail_1");
|
||||
const detail1CgId = WfForm.convertFieldNameToId("cgddzbid", "detail_1");
|
||||
|
||||
WfForm.registerCheckEvent(WfForm.OPER_ADDROW + "3", function (callback) {
|
||||
callback();
|
||||
setTimeout(()=>{
|
||||
initDeatail3Date();
|
||||
},5)
|
||||
});
|
||||
// 关联订单变化时将明细四的合同-金额map进行初始化
|
||||
// // 关联订单变化时将明细四的合同-金额map进行初始化
|
||||
// WfForm.bindFieldChangeEvent(relationOrder, function(obj,id,value){
|
||||
// setTimeout(()=>{
|
||||
// initDetail4Map();
|
||||
// changeDetail3SpMoney();
|
||||
// },2000);
|
||||
// });
|
||||
|
||||
WfForm.bindFieldChangeEvent(relationOrder, function (obj, id, value) {
|
||||
setTimeout(() => {
|
||||
initDetail4Map();
|
||||
changeDetail3SpMoney();
|
||||
changeDetail1ApplyAMount();
|
||||
}, 2000);
|
||||
});
|
||||
WfForm.bindDetailFieldChangeEvent(detail3ApplyMoneyField, function () {
|
||||
setTimeout(() => {
|
||||
changeDetail1ApplyAMount();
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
|
||||
WfForm.bindFieldChangeEvent(`${yjfksj},${bl}`, function(obj,id,value){
|
||||
initDeatail3Date();
|
||||
|
@ -123,21 +142,27 @@ function initDetail4Map() {
|
|||
console.log('detail4Map ', detail4Map)
|
||||
}
|
||||
|
||||
const detail3ApplyMoneyField = WfForm.convertFieldNameToId("bcfkje", "detail_3");
|
||||
const detail3CgId = WfForm.convertFieldNameToId("cgddzbid", "detail_3");
|
||||
const detail3Bl = WfForm.convertFieldNameToId('bcfkbl', "detail_3");
|
||||
let detailBlMap = new Map();
|
||||
const detail1Bl = WfForm.convertFieldNameToId('fkbl', "detail_1");
|
||||
const detail1CgId = WfForm.convertFieldNameToId("cgddzbid", "detail_1");
|
||||
|
||||
WfForm.bindDetailFieldChangeEvent(detail3ApplyMoneyField, (id, rowIndex, value) => {
|
||||
setTimeout(()=>{
|
||||
let detail3RowArr = WfForm.getDetailAllRowIndexStr('detail_3').split(",");
|
||||
detailBlMap = new Map();
|
||||
for (let i = 0; i < detail3RowArr.length; i++) {
|
||||
let rowIndex = detail3RowArr[i];
|
||||
if (rowIndex !== "") {
|
||||
let bl = parseFloat(WfForm.getFieldValue(`${detail3Bl}_${rowIndex}`));
|
||||
let blStr = WfForm.getFieldValue(`${detail3Bl}_${rowIndex}`);
|
||||
if(blStr == ''){
|
||||
console.log('111')
|
||||
continue;
|
||||
}
|
||||
let bl = parseFloat(blStr);
|
||||
console.log('bl => ' , bl);
|
||||
let cg = WfForm.getFieldValue(`${detail3CgId}_${rowIndex}`);
|
||||
let mapVal = parseFloat(detailBlMap.get(cg) ?? 0) + bl;
|
||||
let mapVal = detailBlMap.get(cg);
|
||||
if(!mapVal){
|
||||
mapVal = 0;
|
||||
}
|
||||
mapVal+= bl;
|
||||
detailBlMap.set(cg, mapVal);
|
||||
}
|
||||
}
|
||||
|
@ -151,9 +176,87 @@ WfForm.bindDetailFieldChangeEvent(detail3ApplyMoneyField, (id, rowIndex, value)
|
|||
WfForm.changeFieldValue(`${detail1Bl}_${rowIndex}`, {value: val})
|
||||
}
|
||||
}
|
||||
},300);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 明细3合同总金额
|
||||
const detail3AmountField = WfForm.convertFieldNameToId("htzje", "detail_3");
|
||||
// 明细3订单号字段
|
||||
const detail3OrderField = WfForm.convertFieldNameToId("ddh","detail_3");
|
||||
// 明细1本次付款金额字段
|
||||
const detail1ApplyAmountField = WfForm.convertFieldNameToId("bcsqfkje","detail_1");
|
||||
// 明细1含税金额
|
||||
const detail1AmountTaxField = WfForm.convertFieldNameToId("ddmxxj","detail_1");
|
||||
// 明细1订单号
|
||||
const detail1OrderField = WfForm.convertFieldNameToId("ddh","detail_1");
|
||||
// 明细1预计付款日期
|
||||
const detail1ApplyDate = WfForm.convertFieldNameToId("yjfkrq","detail_1");
|
||||
function changeDetail1ApplyAMount(){
|
||||
let detail3RowArr = WfForm.getDetailAllRowIndexStr('detail_3').split(",");
|
||||
// 明细3 订单号-合同总金额map
|
||||
let detail3ContractAmountMap = new Map();
|
||||
let detail3ApplyAmountMap = new Map();
|
||||
let detail3ApplyMoneyField = WfForm.convertFieldNameToId("bcfkje", "detail_3");
|
||||
for (let i = 0; i < detail3RowArr.length; i++) {
|
||||
let rowIndex = detail3RowArr[i];
|
||||
if (rowIndex !== "") {
|
||||
let detail3Order = WfForm.getFieldValue(`${detail3OrderField}_${rowIndex}`);
|
||||
if(!detail3ContractAmountMap.has(detail3Order)){
|
||||
detail3ContractAmountMap.set(detail3Order, parseFloat(WfForm.getFieldValue(`${detail3AmountField}_${rowIndex}`)));
|
||||
}
|
||||
let detail3Amount = parseFloat(WfForm.getFieldValue(`${detail3ApplyMoneyField}_${rowIndex}`));
|
||||
let sum = detail3ApplyAmountMap.get(detail3Order) ?? 0;
|
||||
detail3ApplyAmountMap.set(detail3Order, sum + detail3Amount);
|
||||
}
|
||||
}
|
||||
console.log('detail3ContractAmountMap : ', detail3ContractAmountMap);
|
||||
console.log('detail3ApplyAmountMap : ', detail3ApplyAmountMap);
|
||||
let detail1RowArr = WfForm.getDetailAllRowIndexStr('detail_1').split(",");
|
||||
for (let i = 0; i < detail1RowArr.length; i++) {
|
||||
let rowIndex = detail1RowArr[i];
|
||||
if (rowIndex !== "") {
|
||||
let detail1Order =WfForm.getFieldValue(`${detail1OrderField}_${rowIndex}`);
|
||||
console.log('detail1Order ', detail1Order);
|
||||
// 含税金额
|
||||
let detail1AmountTax = parseFloat(WfForm.getFieldValue(`${detail1AmountTaxField}_${rowIndex}`) ?? 0);
|
||||
console.log('detail1AmountTax ', detail1AmountTax);
|
||||
// 本次付款金额和
|
||||
let applySum = parseFloat(detail3ApplyAmountMap.get(detail1Order) ?? 0);
|
||||
console.log('applySum ', applySum);
|
||||
// 合同总金额
|
||||
let contractAmount = parseFloat(detail3ContractAmountMap.get(detail1Order) ?? 0);
|
||||
console.log('contractAmount ', contractAmount);
|
||||
let val = (applySum / contractAmount) * detail1AmountTax;
|
||||
console.log('计算金额 : ', val)
|
||||
WfForm.changeFieldValue(`${detail1ApplyAmountField}_${rowIndex}`, {value: val})
|
||||
}
|
||||
}
|
||||
}
|
||||
WfForm.bindDetailFieldChangeEvent(detail3Yqfkrq,()=>{
|
||||
initDetail1ApplyDate();
|
||||
});
|
||||
function initDetail1ApplyDate(){
|
||||
let detail3RowArr = WfForm.getDetailAllRowIndexStr('detail_3').split(",");
|
||||
let detail3DateMap = new Map();
|
||||
for (let i = 0; i < detail3RowArr.length; i++) {
|
||||
let rowIndex = detail3RowArr[i];
|
||||
if (rowIndex !== "") {
|
||||
let detail3Order = WfForm.getFieldValue(`${detail3OrderField}_${rowIndex}`);
|
||||
if(!detail3DateMap.has(detail3Order)){
|
||||
detail3DateMap.set(detail3Order, WfForm.getFieldValue(`${detail3Yqfkrq}_${rowIndex}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('detail3DateMap ', detail3DateMap);
|
||||
let detail1RowArr = WfForm.getDetailAllRowIndexStr('detail_1').split(",");
|
||||
for (let i = 0; i < detail1RowArr.length; i++) {
|
||||
let rowIndex = detail1RowArr[i];
|
||||
if (rowIndex !== "") {
|
||||
let detail1Order =WfForm.getFieldValue(`${detail1OrderField}_${rowIndex}`);
|
||||
WfForm.changeFieldValue(`${detail1ApplyDate}_${rowIndex}`, {value: detail3DateMap.get(detail1Order)})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
// 首台销售日期
|
||||
const firstSaleDateField = WfForm.convertFieldNameToId("stxsrq");
|
||||
// 跟踪时间
|
||||
const trackTimeField = WfForm.convertFieldNameToId("gzsj");
|
||||
// 跟踪时间为三个月以内
|
||||
const threeMonthIndex = 1;
|
||||
// 是否提交等待节点
|
||||
const submitWaitNode = WfForm.convertFieldNameToId("sftjddjd");
|
||||
// 下次超时提醒日期
|
||||
const timeoutRemindDateFiled = WfForm.convertFieldNameToId("cstxrq");
|
||||
// 跟踪天数
|
||||
const trackingDays = WfForm.getFieldValue(trackTimeField) <= 1 ? 15 : 30;
|
||||
// 跟踪触发行数
|
||||
const trackingLineField = WfForm.convertFieldNameToId("gzcfxs");
|
||||
$(() => {
|
||||
let detail2LineNum = WfForm.getDetailRowCount("detail_2");
|
||||
// let firstTrack = Boolean(true);
|
||||
// if (new Date(firstSaleDate) < new Date(currentDate) && dayDiff > 0) {
|
||||
// firstTrack = false;
|
||||
// }
|
||||
// console.log('firstTrack ', firstTrack)
|
||||
// 到达节点次数
|
||||
const nodeNum = getNodeNum();
|
||||
let trackingLine = parseInt(WfForm.getFieldValue(trackingLineField));
|
||||
// 如果不是则自动添加一行明细让他自己填写
|
||||
if (detail2LineNum < trackingLine && detail2LineNum < nodeNum) {
|
||||
console.log('添加一行明细!');
|
||||
WfForm.addDetailRow("detail_2", {});
|
||||
}
|
||||
if(detail2LineNum >= trackingLine){
|
||||
WfForm.changeFieldValue(submitWaitNode, {value: 1});
|
||||
WfForm.changeFieldValue(timeoutRemindDateFiled, {value: ''});
|
||||
return;
|
||||
}
|
||||
initTimeoutDate();
|
||||
WfForm.bindFieldChangeEvent(`${firstSaleDateField},${trackTimeField}`,()=>{
|
||||
initTimeoutDate();
|
||||
});
|
||||
});
|
||||
|
||||
function getNodeNum(){
|
||||
let firstSaleDate = WfForm.getFieldValue(firstSaleDateField);
|
||||
console.log('首台销售日期 ', firstSaleDate);
|
||||
let currentDate = getCurrentDate();
|
||||
let dayDiff = getDaysDiff(firstSaleDate, currentDate);
|
||||
console.log('当前天数与首台销售日期相差天数 : ', dayDiff)
|
||||
return Math.floor(dayDiff / trackingDays) + 1;
|
||||
}
|
||||
|
||||
function initTimeoutDate(){
|
||||
console.log('==== initTimeoutDate begin ====')
|
||||
let firstSaleDate = WfForm.getFieldValue(firstSaleDateField);
|
||||
const nodeNum = getNodeNum();
|
||||
console.log('到达节点次数 ', nodeNum);
|
||||
console.log('跟踪天数 ', trackingDays);
|
||||
let computeTimeoutDate = addDays(firstSaleDate, nodeNum * trackingDays);
|
||||
console.log('计算下次超时日期 ', computeTimeoutDate);
|
||||
let trackingLine = parseInt(WfForm.getFieldValue(trackingLineField));
|
||||
let detail2LineNum = WfForm.getDetailRowCount("detail_2");
|
||||
setTimeout(()=>{
|
||||
WfForm.changeFieldValue(timeoutRemindDateFiled, {value: computeTimeoutDate});
|
||||
// 判断流程提交走向
|
||||
console.log('主表跟踪触发行数 : ', trackingLine)
|
||||
if (nodeNum >= trackingLine) {
|
||||
console.log('nodeNum >= trackingLine');
|
||||
WfForm.changeFieldValue(submitWaitNode, {value: 1});
|
||||
WfForm.changeFieldValue(timeoutRemindDateFiled, {value: ''});
|
||||
WfForm.registerCheckEvent(WfForm.OPER_SUBMIT, function (callback) {
|
||||
detail2LineNum = WfForm.getDetailRowCount("detail_2");
|
||||
if (detail2LineNum < trackingLine) {
|
||||
WfForm.showMessage('请填写明细表信息!');
|
||||
detail2LineNum = WfForm.getDetailRowCount("detail_2");
|
||||
for (let i = 0; i < trackingLine - parseInt(detail2LineNum); i++) {
|
||||
WfForm.addDetailRow("detail_2", {});
|
||||
}
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
});
|
||||
} else {
|
||||
WfForm.changeFieldValue(submitWaitNode, {value: 0});
|
||||
}
|
||||
console.log('==== initTimeoutDate end ====')
|
||||
},10);
|
||||
}
|
||||
|
||||
function getDaysDiff(date1, date2) {
|
||||
date1 = new Date(date1);
|
||||
date2 = new Date(date2);
|
||||
const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
|
||||
const timeDiff = Math.abs(date1.getTime() - date2.getTime()); // 两个日期对象的毫秒数差值
|
||||
// 将毫秒数差值转换为天数差值并四舍五入
|
||||
return Math.round(timeDiff / oneDay);
|
||||
}
|
||||
|
||||
function getCurrentDate() {
|
||||
return parseDate(new Date());
|
||||
}
|
||||
|
||||
function parseDate(date) {
|
||||
const currentYear = date.getFullYear();
|
||||
const currentMonth = date.getMonth() + 1; // getMonth()返回0~11,需要加1
|
||||
const currentDay = date.getDate();
|
||||
return currentYear + '-' + currentMonth + '-' + currentDay;
|
||||
}
|
||||
|
||||
function addDays(date, days) {
|
||||
const newDate = new Date(date);
|
||||
newDate.setDate(newDate.getDate() + days);
|
||||
console.log('newDate ', newDate)
|
||||
return parseDate(newDate);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -681,3 +681,61 @@ $(() => {
|
|||
})
|
||||
|
||||
/* ******************* 明细数据数量统计添加 end ******************* */
|
||||
|
||||
|
||||
/* ******************* 计算年月日 start ******************* */
|
||||
|
||||
$(() => {
|
||||
const config = [{
|
||||
// 源字段
|
||||
sourceField: '',
|
||||
// 目标字段
|
||||
targetField: '',
|
||||
// 日期加月份字段
|
||||
numberField: ''
|
||||
}, {
|
||||
sourceField: '',
|
||||
targetField: '',
|
||||
numberField: ''
|
||||
}]
|
||||
|
||||
runJs();
|
||||
|
||||
function runJs() {
|
||||
config.forEach(item => {
|
||||
bindAction(item)
|
||||
})
|
||||
}
|
||||
|
||||
function bindAction(configItem) {
|
||||
let fieldId = WfForm.convertFieldNameToId(configItem.numberField)
|
||||
WfForm.bindFieldChangeEvent(fieldId, (obj, id, value) => {
|
||||
if ("" == value) {
|
||||
WfForm.changeFieldValue(WfForm.convertFieldNameToId(configItem.targetField, {value: ""}))
|
||||
return
|
||||
}
|
||||
let sourceValue = WfForm.getFieldValue(WfForm.convertFieldNameToId(configItem.sourceField));
|
||||
let date = new Date(sourceValue)
|
||||
date.setMonth(date.getMonth() + +value)
|
||||
let objectDate = new Date();
|
||||
|
||||
|
||||
let day = objectDate.getDate();
|
||||
let month = objectDate.getMonth() + 1;
|
||||
let year = objectDate.getFullYear();
|
||||
WfForm.changeFieldValue(WfForm.convertFieldNameToId(configItem.targetField, {
|
||||
value: `${year}-${fullNum(month)}-${fullNum(day)}`
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
function fullNum(i) {
|
||||
if (i <= 9) {
|
||||
return '0' + i
|
||||
} else {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
/* ******************* 计算年月日 end ******************* */
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,25 @@
|
|||
package aiyh.utils;
|
||||
|
||||
import aiyh.utils.tool.org.apache.commons.jexl3.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <h1>脚本工具</h1>
|
||||
*
|
||||
* <p>create: 2023/3/3 23:03</p>
|
||||
*
|
||||
* @author youHong.ai
|
||||
*/
|
||||
public class ScriptUtil {
|
||||
private static final JexlEngine jexl = new JexlBuilder().create();
|
||||
|
||||
public static Object invokeScript(String script, Map<String, Object> params) {
|
||||
JexlContext jc = new MapContext();
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
jc.set(entry.getKey(), entry.getValue());
|
||||
}
|
||||
JexlExpression expression = jexl.createExpression(script);
|
||||
return expression.evaluate(jc);
|
||||
}
|
||||
}
|
|
@ -3751,6 +3751,32 @@ public class Util extends weaver.general.Util {
|
|||
return pathParamMap;
|
||||
}
|
||||
|
||||
public static <T> T getClassInstance(String classPath, Class<T> t) {
|
||||
Class<?> aClass;
|
||||
try {
|
||||
aClass = Class.forName(classPath);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException("未能找到自定义接口:" + classPath);
|
||||
}
|
||||
if (!t.isAssignableFrom(aClass)) {
|
||||
throw new IllegalArgumentException("自定义接口:" + classPath + " 不是"
|
||||
+ t.getName() + "的子类或实现类!");
|
||||
}
|
||||
Constructor<?> constructor;
|
||||
try {
|
||||
constructor = aClass.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IllegalArgumentException(classPath + "没有空参构造方法,无法获取构造方法对象!");
|
||||
}
|
||||
T o;
|
||||
try {
|
||||
o = (T) constructor.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalArgumentException("无法构造" + classPath + "对象!");
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
public static Object executeActionProcess(String process, RequestInfo requestInfo) {
|
||||
if (StringUtils.isNullOrEmpty(process)) {
|
||||
return null;
|
||||
|
|
|
@ -2,6 +2,7 @@ package aiyh.utils.fileUtil.pdf;
|
|||
|
||||
import aiyh.utils.Util;
|
||||
import aiyh.utils.excention.CustomerException;
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollectionUtil;
|
||||
import com.itextpdf.text.DocumentException;
|
||||
import com.itextpdf.text.Image;
|
||||
import com.itextpdf.text.pdf.PdfContentByte;
|
||||
|
@ -107,6 +108,9 @@ public class PdfUtil {
|
|||
}
|
||||
InputStream inputStream = ImageFileManager.getInputStreamById(pdfImageFileId);
|
||||
List<PdfPointItem> keywordPoints = findKeywordPoints(inputStream, keyword);
|
||||
if (CollectionUtil.isEmpty(keywordPoints)) {
|
||||
throw new CustomerException("关键字定位异常,未发现关键字!");
|
||||
}
|
||||
PdfReader pdfReader = null;
|
||||
Image image = null;
|
||||
try {
|
||||
|
|
|
@ -32,6 +32,7 @@ import weaver.file.ImageFileManager;
|
|||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.io.*;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
@ -127,7 +128,11 @@ public class HttpUtils {
|
|||
builder.append("&");
|
||||
builder.append(entry.getKey());
|
||||
builder.append("=");
|
||||
builder.append(entry.getValue());
|
||||
try {
|
||||
builder.append(URLEncoder.encode(Util.null2String(entry.getValue()), "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
builder.append(entry.getKey());
|
||||
}
|
||||
}
|
||||
return removeSeparator(builder);
|
||||
}
|
||||
|
|
|
@ -27,11 +27,7 @@ public class FloatTypeHandler implements TypeHandler {
|
|||
}
|
||||
return 0.0F;
|
||||
}
|
||||
float v = Float.parseFloat(string);
|
||||
if (!string.equals(String.valueOf(v))) {
|
||||
return Double.parseDouble(string);
|
||||
}
|
||||
return v;
|
||||
return Float.parseFloat(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -45,11 +41,8 @@ public class FloatTypeHandler implements TypeHandler {
|
|||
}
|
||||
return 0.0F;
|
||||
}
|
||||
float v = Float.parseFloat(string);
|
||||
if (!string.equals(String.valueOf(v))) {
|
||||
return Double.parseDouble(string);
|
||||
}
|
||||
return v;
|
||||
|
||||
return Float.parseFloat(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,11 +56,8 @@ public class FloatTypeHandler implements TypeHandler {
|
|||
}
|
||||
return 0.0F;
|
||||
}
|
||||
float v = Float.parseFloat(string);
|
||||
if (!string.equals(String.valueOf(v))) {
|
||||
return Double.parseDouble(string);
|
||||
}
|
||||
return v;
|
||||
|
||||
return Float.parseFloat(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -81,11 +71,8 @@ public class FloatTypeHandler implements TypeHandler {
|
|||
}
|
||||
return 0.0F;
|
||||
}
|
||||
float v = Float.parseFloat(string);
|
||||
if (!string.equals(String.valueOf(v))) {
|
||||
return Double.parseDouble(string);
|
||||
}
|
||||
return v;
|
||||
|
||||
return Float.parseFloat(string);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
package aiyh.utils.recordset;
|
||||
|
||||
import aiyh.utils.excention.CustomerException;
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollectionUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <h1>构建sql</h1>
|
||||
*
|
||||
* <p>create: 2023/5/12 20:51</p>
|
||||
*
|
||||
* @author youHong.ai
|
||||
*/
|
||||
public class MapperBuilderSql {
|
||||
|
||||
/**
|
||||
* <h2>构建更新sql</h2>
|
||||
*
|
||||
* @param table 表名称
|
||||
* @param param 参数
|
||||
* @return 构建的sql
|
||||
*/
|
||||
public static String builderUpdateSql(String table, Map<String, Object> param) {
|
||||
return builderUpdateSql(table, param, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* <h2>构建更新sql</h2>
|
||||
*
|
||||
* @param table 表名称
|
||||
* @param param 参数
|
||||
* @return 构建的sql
|
||||
*/
|
||||
public static String builderUpdateSql(String table, Map<String, Object> param, String paramPrefix) {
|
||||
if (StrUtil.isBlank(table) || CollectionUtil.isEmpty(param)) {
|
||||
throw new CustomerException("tableName or param can not to be null!");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("update ").append(table).append(" set ");
|
||||
for (Map.Entry<String, Object> entry : param.entrySet()) {
|
||||
sb.append(" ")
|
||||
.append(entry.getKey())
|
||||
.append(" = ")
|
||||
.append("#{");
|
||||
if (StrUtil.isNotBlank(paramPrefix)) {
|
||||
sb.append(paramPrefix).append(".");
|
||||
}
|
||||
sb.append(entry.getKey())
|
||||
.append("}")
|
||||
.append(",");
|
||||
}
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <h2>构建插入sql</h2>
|
||||
*
|
||||
* @param table 表名称
|
||||
* @param param 参数
|
||||
* @return 构建的sql
|
||||
*/
|
||||
public static String builderInsertSql(String table, Map<String, Object> param) {
|
||||
return builderInsertSql(table, param, "");
|
||||
}
|
||||
|
||||
public static String builderInsertSql(String table, Map<String, Object> param, String paramPrefix) {
|
||||
if (StrUtil.isBlank(table) || CollectionUtil.isEmpty(param)) {
|
||||
throw new CustomerException("tableName or param can not to be null!");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder sbValue = new StringBuilder();
|
||||
sb.append("insert into ").append(table).append(" (");
|
||||
sbValue.append(") values ( ");
|
||||
for (Map.Entry<String, Object> entry : param.entrySet()) {
|
||||
sb.append(entry.getKey()).append(" ,");
|
||||
sbValue.append(" #{");
|
||||
if (StrUtil.isNotBlank(paramPrefix)) {
|
||||
sbValue.append(paramPrefix).append(".");
|
||||
}
|
||||
sbValue.append(entry.getKey()).append("},");
|
||||
}
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sbValue.deleteCharAt(sbValue.length() - 1);
|
||||
sb.append(sbValue).append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String builderWhereAnd(Map<String, Object> param, boolean containsWhere) {
|
||||
return builderWhereAnd(param, "whereParam", containsWhere);
|
||||
}
|
||||
|
||||
public static String builderWhereAnd(Map<String, Object> param) {
|
||||
return builderWhereAnd(param, "whereParam", true);
|
||||
}
|
||||
|
||||
public static String builderNoWhereAndEn(Map<String, Object> param, boolean containsWhere) {
|
||||
return builderWhereAnd(param, "", containsWhere);
|
||||
}
|
||||
|
||||
public static String builderNoWhereAndEn(Map<String, Object> param) {
|
||||
return builderWhereAnd(param, "", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* <h2>构建and条件</h2>
|
||||
*
|
||||
* @param param 参数
|
||||
* @param wherePrefix 条件拼接前缀
|
||||
* @param containsWhere 是否包含where
|
||||
* @return 构建的where条件
|
||||
*/
|
||||
public static String builderWhereAnd(Map<String, Object> param, String wherePrefix, boolean containsWhere) {
|
||||
if (CollectionUtil.isEmpty(param)) {
|
||||
throw new CustomerException("tableName or param can not to be null!");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (containsWhere) {
|
||||
sb.append(" where ");
|
||||
}
|
||||
for (Map.Entry<String, Object> entry : param.entrySet()) {
|
||||
sb.append(entry.getKey()).append(" = #{");
|
||||
if (StrUtil.isNotBlank(wherePrefix)) {
|
||||
sb.append(wherePrefix).append(".");
|
||||
}
|
||||
sb.append(entry.getKey()).append("}").append(" and ");
|
||||
}
|
||||
sb.deleteCharAt(sb.length() - 5);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -460,7 +460,7 @@ public class ResultMapper {
|
|||
}
|
||||
if ("int".equalsIgnoreCase(columnType) || "long".equalsIgnoreCase(columnType) || "number".equalsIgnoreCase(columnType) || "MEDIUMINT".equalsIgnoreCase(columnType) || "TINYINT".equalsIgnoreCase(columnType) || "SMALLINT".equalsIgnoreCase(columnType) || "BIGINT".equalsIgnoreCase(columnType) || "INTEGER".equalsIgnoreCase(columnType)) {
|
||||
if (enable) {
|
||||
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getInt(i + 1));
|
||||
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getInt(columnName[i]));
|
||||
continue;
|
||||
}
|
||||
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
|
||||
|
@ -473,11 +473,11 @@ public class ResultMapper {
|
|||
}
|
||||
if ("FLOAT".equalsIgnoreCase(columnType) || "DOUBLE".equalsIgnoreCase(columnType) || "DECIMAL".equalsIgnoreCase(columnType)) {
|
||||
if (enable) {
|
||||
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(i + 1));
|
||||
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(columnName[i]));
|
||||
continue;
|
||||
}
|
||||
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
|
||||
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(i + 1));
|
||||
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(columnName[i]));
|
||||
}
|
||||
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getString(i + 1));
|
||||
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getString(i + 1));
|
||||
|
@ -507,7 +507,7 @@ public class ResultMapper {
|
|||
}
|
||||
}
|
||||
if (enable) {
|
||||
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(i + 1));
|
||||
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(columnName[i]));
|
||||
continue;
|
||||
}
|
||||
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
|
||||
|
@ -569,7 +569,9 @@ public class ResultMapper {
|
|||
cassociationValue = paramType.get(declaredField.getType()).apply(String.valueOf(cassociationValue));
|
||||
}
|
||||
try {
|
||||
if (Objects.nonNull(cassociationValue)) {
|
||||
propertyDescriptor.getWriteMethod().invoke(o, cassociationValue);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Util.getLogger().error("实体数据写入报错:" + fieldName + " => " + value);
|
||||
if (value != null) {
|
||||
|
@ -584,7 +586,9 @@ public class ResultMapper {
|
|||
if (collectionMapping != null) {
|
||||
Object collection = collection(rs, collectionMapping, method);
|
||||
try {
|
||||
if (Objects.nonNull(value)) {
|
||||
propertyDescriptor.getWriteMethod().invoke(o, collection);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Util.getLogger().error("实体数据写入报错:" + fieldName + " => " + value);
|
||||
if (value != null) {
|
||||
|
@ -647,7 +651,6 @@ public class ResultMapper {
|
|||
Association[] mappings = annotation.value();
|
||||
Association mapping = null;
|
||||
for (Association item : mappings) {
|
||||
Util.getLogger().info("column: " + item.column() + " ===property: " + item.property() + " ====fieldName: " + filedName);
|
||||
String property = isMap ? item.column() : item.property();
|
||||
if (isMap ? filedName.equalsIgnoreCase(property) : filedName.equals(property)) {
|
||||
mapping = item;
|
||||
|
@ -660,7 +663,6 @@ public class ResultMapper {
|
|||
Id id = annotation.id();
|
||||
String column = annotation.column();
|
||||
String columnValue = rs.getString(column);
|
||||
Util.getLogger().info(Arrays.toString(rs.getColumnName()));
|
||||
if (Objects.isNull(columnValue) || "".equals(columnValue)) {
|
||||
columnValue = rs.getString(column.toUpperCase());
|
||||
}
|
||||
|
|
|
@ -5,18 +5,15 @@ import aiyh.utils.Util;
|
|||
import aiyh.utils.mapUtil.UtilHashMap;
|
||||
import aiyh.utils.mapUtil.UtilLinkedHashMap;
|
||||
import aiyh.utils.sqlUtil.builderSql.BuilderSql;
|
||||
import aiyh.utils.sqlUtil.sqlResult.impl.PrepSqlResultImpl;
|
||||
import aiyh.utils.sqlUtil.sqlResult.impl.BatchSqlResultImpl;
|
||||
import aiyh.utils.sqlUtil.sqlResult.impl.PrepSqlResultImpl;
|
||||
import aiyh.utils.sqlUtil.whereUtil.Where;
|
||||
import aiyh.utils.sqlUtil.whereUtil.impl.WhereImpl;
|
||||
import weaver.conn.RecordSet;
|
||||
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
@ -29,7 +26,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
|
||||
public class BuilderSqlImpl implements BuilderSql {
|
||||
private String DB_TYPE;
|
||||
private final String DB_TYPE;
|
||||
|
||||
{
|
||||
// 获取当前数据库的类型
|
||||
|
@ -38,6 +35,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 构建插入语句
|
||||
*
|
||||
* @param tableName 数据库表名
|
||||
* @param mapConfig 数据库字段和值
|
||||
* @return 自定义SQL实体类
|
||||
|
@ -66,6 +64,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 通过实体类构建插入SQL
|
||||
*
|
||||
* @param tableName 数据库表名
|
||||
* @param t 实体类对象
|
||||
* @param <T> 实体类对象泛型
|
||||
|
@ -109,6 +108,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 构建批量插入SQL
|
||||
*
|
||||
* @param tableName 表名
|
||||
* @param mapListConfig 表对应的字段和值映射list
|
||||
* @return 自定义批量SQL实体类
|
||||
|
@ -145,6 +145,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 构建批量插入SQL
|
||||
*
|
||||
* @param tableName 数据库表名
|
||||
* @param list 实体类数组
|
||||
* @param <T> 实体类泛型
|
||||
|
@ -195,6 +196,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 构建更新语句
|
||||
*
|
||||
* @param tableName 表名
|
||||
* @param mapConfig 表名所对应键值对
|
||||
* @param where 更新数据的条件
|
||||
|
@ -225,6 +227,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 构建更新SQL语句
|
||||
*
|
||||
* @param tableName 数据库表名
|
||||
* @param t 实体类对象
|
||||
* @param where 更新条件对象
|
||||
|
@ -308,6 +311,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 通过实体类构建批量更新SQL
|
||||
*
|
||||
* @param tableName 数据库表名
|
||||
* @param list 实体类集合
|
||||
* @param whereList 更新条件集合,一一对应更新数据集合
|
||||
|
@ -361,6 +365,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 构建插入SQL语句
|
||||
*
|
||||
* @param tableName 表名
|
||||
* @param mapConfig 参数
|
||||
* @return 拼接好的SQL
|
||||
|
@ -390,6 +395,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 构建更新SQL语句
|
||||
*
|
||||
* @param tableName 表名
|
||||
* @param mapConfig 参数
|
||||
* @return 拼接好的SQL
|
||||
|
@ -417,10 +423,9 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 验证构建SQL参数的,并且过滤到为null的数据
|
||||
*
|
||||
* @param map 验证SQL参数map对象
|
||||
* @return 验证后的UtilHashMap
|
||||
*/
|
||||
|
@ -436,6 +441,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 验证批量SQL构建的数据
|
||||
*
|
||||
* @param mapList 批量构建SQL的的工具
|
||||
* @return 验证和过滤后的数据
|
||||
*/
|
||||
|
@ -456,6 +462,7 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
|
||||
/**
|
||||
* 验证where条件是否符合
|
||||
*
|
||||
* @param where where 条件对象
|
||||
*/
|
||||
private void verifyWhere(Where where) {
|
||||
|
@ -463,8 +470,10 @@ public class BuilderSqlImpl implements BuilderSql {
|
|||
throw new RuntimeException("where为null! where is null!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证where条件集合是否符合
|
||||
*
|
||||
* @param whereList where 条件对象集合
|
||||
*/
|
||||
private void verifyWhereList(List<Where> whereList) {
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 常用Content-Type类型枚举
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.0.11
|
||||
*/
|
||||
public enum ContentType {
|
||||
|
||||
/**
|
||||
* 标准表单编码,当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2…)
|
||||
*/
|
||||
FORM_URLENCODED("application/x-www-form-urlencoded"),
|
||||
/**
|
||||
* 文件上传编码,浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition,并加上分割符(boundary)
|
||||
*/
|
||||
MULTIPART("multipart/form-data"),
|
||||
/**
|
||||
* Rest请求JSON编码
|
||||
*/
|
||||
JSON("application/json"),
|
||||
/**
|
||||
* Rest请求XML编码
|
||||
*/
|
||||
XML("application/xml"),
|
||||
/**
|
||||
* text/plain编码
|
||||
*/
|
||||
TEXT_PLAIN("text/plain"),
|
||||
/**
|
||||
* Rest请求text/xml编码
|
||||
*/
|
||||
TEXT_XML("text/xml"),
|
||||
/**
|
||||
* text/html编码
|
||||
*/
|
||||
TEXT_HTML("text/html"),
|
||||
/**
|
||||
* application/octet-stream编码
|
||||
*/
|
||||
OCTET_STREAM("application/octet-stream");
|
||||
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param value ContentType值
|
||||
*/
|
||||
ContentType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取value值
|
||||
*
|
||||
* @return value值
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出Content-Type字符串,附带编码信息
|
||||
*
|
||||
* @param charset 编码
|
||||
* @return Content-Type字符串
|
||||
*/
|
||||
public String toString(Charset charset) {
|
||||
return build(this.value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为默认Content-Type,默认包括{@code null}和application/x-www-form-urlencoded
|
||||
*
|
||||
* @param contentType 内容类型
|
||||
* @return 是否为默认Content-Type
|
||||
* @since 4.1.5
|
||||
*/
|
||||
public static boolean isDefault(String contentType) {
|
||||
return null == contentType || isFormUrlEncode(contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为application/x-www-form-urlencoded
|
||||
*
|
||||
* @param contentType 内容类型
|
||||
* @return 是否为application/x-www-form-urlencoded
|
||||
*/
|
||||
public static boolean isFormUrlEncode(String contentType) {
|
||||
return StrUtil.startWithIgnoreCase(contentType, FORM_URLENCODED.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求参数的body中判断请求的Content-Type类型,支持的类型有:
|
||||
*
|
||||
* <pre>
|
||||
* 1. application/json
|
||||
* 1. application/xml
|
||||
* </pre>
|
||||
*
|
||||
* @param body 请求参数体
|
||||
* @return Content-Type类型,如果无法判断返回null
|
||||
*/
|
||||
public static ContentType get(String body) {
|
||||
ContentType contentType = null;
|
||||
if (StrUtil.isNotBlank(body)) {
|
||||
char firstChar = body.charAt(0);
|
||||
switch (firstChar) {
|
||||
case '{':
|
||||
case '[':
|
||||
// JSON请求体
|
||||
contentType = JSON;
|
||||
break;
|
||||
case '<':
|
||||
// XML请求体
|
||||
contentType = XML;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出Content-Type字符串,附带编码信息
|
||||
*
|
||||
* @param contentType Content-Type类型
|
||||
* @param charset 编码
|
||||
* @return Content-Type字符串
|
||||
* @since 4.5.4
|
||||
*/
|
||||
public static String build(String contentType, Charset charset) {
|
||||
return StrUtil.format("{};charset={}", contentType, charset.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出Content-Type字符串,附带编码信息
|
||||
*
|
||||
* @param contentType Content-Type 枚举类型
|
||||
* @param charset 编码
|
||||
* @return Content-Type字符串
|
||||
* @since 5.7.15
|
||||
*/
|
||||
public static String build(ContentType contentType, Charset charset) {
|
||||
return build(contentType.getValue(), charset);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollectionUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.map.MapUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* 全局头部信息<br>
|
||||
* 所有Http请求将共用此全局头部信息,除非在{@link HttpRequest}中自定义头部信息覆盖之
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public enum GlobalHeaders {
|
||||
INSTANCE;
|
||||
|
||||
/**
|
||||
* 存储头信息
|
||||
*/
|
||||
final Map<String, List<String>> headers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
GlobalHeaders() {
|
||||
putDefault(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入默认的头部信息
|
||||
*
|
||||
* @param isReset 是否重置所有头部信息(删除自定义保留默认)
|
||||
* @return this
|
||||
*/
|
||||
public GlobalHeaders putDefault(boolean isReset) {
|
||||
// 解决HttpURLConnection中无法自定义Host等头信息的问题
|
||||
// https://stackoverflow.com/questions/9096987/how-to-overwrite-http-header-host-in-a-httpurlconnection/9098440
|
||||
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
|
||||
|
||||
// 解决server certificate change is restricted during renegotiation问题
|
||||
System.setProperty("jdk.tls.allowUnsafeServerCertChange", "true");
|
||||
System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");
|
||||
|
||||
if (isReset) {
|
||||
this.headers.clear();
|
||||
}
|
||||
|
||||
header(aiyh.utils.tool.cn.hutool.http.Header.ACCEPT, "text/html,application/json,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", true);
|
||||
header(aiyh.utils.tool.cn.hutool.http.Header.ACCEPT_ENCODING, "gzip, deflate", true);
|
||||
header(aiyh.utils.tool.cn.hutool.http.Header.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.8", true);
|
||||
// 此Header只有在post请求中有用,因此在HttpRequest的method方法中设置此头信息,此处去掉
|
||||
// header(Header.CONTENT_TYPE, ContentType.FORM_URLENCODED.toString(CharsetUtil.CHARSET_UTF_8), true);
|
||||
header(aiyh.utils.tool.cn.hutool.http.Header.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36 Hutool", true);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Headers start
|
||||
|
||||
/**
|
||||
* 根据name获取头信息
|
||||
*
|
||||
* @param name Header名
|
||||
* @return Header值
|
||||
*/
|
||||
public String header(String name) {
|
||||
final List<String> values = headerList(name);
|
||||
if (CollectionUtil.isEmpty(values)) {
|
||||
return null;
|
||||
}
|
||||
return values.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据name获取头信息列表
|
||||
*
|
||||
* @param name Header名
|
||||
* @return Header值
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public List<String> headerList(String name) {
|
||||
if (StrUtil.isBlank(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return headers.get(name.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据name获取头信息
|
||||
*
|
||||
* @param name Header名
|
||||
* @return Header值
|
||||
*/
|
||||
public String header(aiyh.utils.tool.cn.hutool.http.Header name) {
|
||||
if (null == name) {
|
||||
return null;
|
||||
}
|
||||
return header(name.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个header<br>
|
||||
* 如果覆盖模式,则替换之前的值,否则加入到值列表中
|
||||
*
|
||||
* @param name Header名
|
||||
* @param value Header值
|
||||
* @param isOverride 是否覆盖已有值
|
||||
* @return this
|
||||
*/
|
||||
synchronized public GlobalHeaders header(String name, String value, boolean isOverride) {
|
||||
if (null != name && null != value) {
|
||||
final List<String> values = headers.get(name.trim());
|
||||
if (isOverride || CollectionUtil.isEmpty(values)) {
|
||||
final ArrayList<String> valueList = new ArrayList<>();
|
||||
valueList.add(value);
|
||||
headers.put(name.trim(), valueList);
|
||||
} else {
|
||||
values.add(value.trim());
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个header<br>
|
||||
* 如果覆盖模式,则替换之前的值,否则加入到值列表中
|
||||
*
|
||||
* @param name Header名
|
||||
* @param value Header值
|
||||
* @param isOverride 是否覆盖已有值
|
||||
* @return this
|
||||
*/
|
||||
public GlobalHeaders header(aiyh.utils.tool.cn.hutool.http.Header name, String value, boolean isOverride) {
|
||||
return header(name.toString(), value, isOverride);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个header<br>
|
||||
* 覆盖模式,则替换之前的值
|
||||
*
|
||||
* @param name Header名
|
||||
* @param value Header值
|
||||
* @return this
|
||||
*/
|
||||
public GlobalHeaders header(aiyh.utils.tool.cn.hutool.http.Header name, String value) {
|
||||
return header(name.toString(), value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个header<br>
|
||||
* 覆盖模式,则替换之前的值
|
||||
*
|
||||
* @param name Header名
|
||||
* @param value Header值
|
||||
* @return this
|
||||
*/
|
||||
public GlobalHeaders header(String name, String value) {
|
||||
return header(name, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求头<br>
|
||||
* 不覆盖原有请求头
|
||||
*
|
||||
* @param headers 请求头
|
||||
* @return this
|
||||
*/
|
||||
public GlobalHeaders header(Map<String, List<String>> headers) {
|
||||
if (MapUtil.isEmpty(headers)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
String name;
|
||||
for (Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
name = entry.getKey();
|
||||
for (String value : entry.getValue()) {
|
||||
this.header(name, StrUtil.nullToEmpty(value), false);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个头信息
|
||||
*
|
||||
* @param name Header名
|
||||
* @return this
|
||||
*/
|
||||
synchronized public GlobalHeaders removeHeader(String name) {
|
||||
if (name != null) {
|
||||
headers.remove(name.trim());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个头信息
|
||||
*
|
||||
* @param name Header名
|
||||
* @return this
|
||||
*/
|
||||
public GlobalHeaders removeHeader(Header name) {
|
||||
return removeHeader(name.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取headers
|
||||
*
|
||||
* @return Headers Map
|
||||
*/
|
||||
public Map<String, List<String>> headers() {
|
||||
return Collections.unmodifiableMap(headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有头信息,包括全局头信息
|
||||
*
|
||||
* @return this
|
||||
* @since 5.7.13
|
||||
*/
|
||||
synchronized public GlobalHeaders clearHeaders() {
|
||||
this.headers.clear();
|
||||
return this;
|
||||
}
|
||||
// ---------------------------------------------------------------- Headers end
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
/**
|
||||
* 全局的拦截器<br>
|
||||
* 包括请求拦截器和响应拦截器
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public enum GlobalInterceptor {
|
||||
INSTANCE;
|
||||
|
||||
private final HttpInterceptor.Chain<aiyh.utils.tool.cn.hutool.http.HttpRequest> requestInterceptors = new HttpInterceptor.Chain<>();
|
||||
private final HttpInterceptor.Chain<aiyh.utils.tool.cn.hutool.http.HttpResponse> responseInterceptors = new HttpInterceptor.Chain<>();
|
||||
|
||||
/**
|
||||
* 设置拦截器,用于在请求前重新编辑请求
|
||||
*
|
||||
* @param interceptor 拦截器实现
|
||||
* @return this
|
||||
*/
|
||||
synchronized public GlobalInterceptor addRequestInterceptor(HttpInterceptor<aiyh.utils.tool.cn.hutool.http.HttpRequest> interceptor) {
|
||||
this.requestInterceptors.addChain(interceptor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置拦截器,用于在响应读取后完成编辑或读取
|
||||
*
|
||||
* @param interceptor 拦截器实现
|
||||
* @return this
|
||||
*/
|
||||
synchronized public GlobalInterceptor addResponseInterceptor(HttpInterceptor<aiyh.utils.tool.cn.hutool.http.HttpResponse> interceptor) {
|
||||
this.responseInterceptors.addChain(interceptor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空请求和响应拦截器
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public GlobalInterceptor clear() {
|
||||
clearRequest();
|
||||
clearResponse();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空请求拦截器
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
synchronized public GlobalInterceptor clearRequest() {
|
||||
requestInterceptors.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空响应拦截器
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
synchronized public GlobalInterceptor clearResponse() {
|
||||
responseInterceptors.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制请求过滤器列表
|
||||
*
|
||||
* @return {@link HttpInterceptor.Chain}
|
||||
*/
|
||||
HttpInterceptor.Chain<aiyh.utils.tool.cn.hutool.http.HttpRequest> getCopiedRequestInterceptor() {
|
||||
final HttpInterceptor.Chain<aiyh.utils.tool.cn.hutool.http.HttpRequest> copied = new HttpInterceptor.Chain<>();
|
||||
for (HttpInterceptor<HttpRequest> interceptor : this.requestInterceptors) {
|
||||
copied.addChain(interceptor);
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制响应过滤器列表
|
||||
*
|
||||
* @return {@link HttpInterceptor.Chain}
|
||||
*/
|
||||
HttpInterceptor.Chain<aiyh.utils.tool.cn.hutool.http.HttpResponse> getCopiedResponseInterceptor() {
|
||||
final HttpInterceptor.Chain<aiyh.utils.tool.cn.hutool.http.HttpResponse> copied = new HttpInterceptor.Chain<>();
|
||||
for (HttpInterceptor<HttpResponse> interceptor : this.responseInterceptors) {
|
||||
copied.addChain(interceptor);
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,539 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.lang.Console;
|
||||
import aiyh.utils.tool.cn.hutool.core.map.SafeConcurrentHashMap;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.CharUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* HTML过滤器,用于去除XSS(Cross Site Scripting) 漏洞隐患。
|
||||
*
|
||||
* <p>
|
||||
* 此类中的方法非线程安全
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* String clean = new HTMLFilter().filter(input);
|
||||
* </pre>
|
||||
* <p>
|
||||
* 此类来自:http://xss-html-filter.sf.net
|
||||
*
|
||||
* @author Joseph O'Connell
|
||||
* @author Cal Hendersen
|
||||
* @author Michael Semb Wever
|
||||
*/
|
||||
public final class HTMLFilter {
|
||||
|
||||
/**
|
||||
* regex flag union representing /si modifiers in php
|
||||
**/
|
||||
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
|
||||
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
|
||||
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
|
||||
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
|
||||
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
|
||||
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
|
||||
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
|
||||
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
|
||||
private static final Pattern P_END_ARROW = Pattern.compile("^>");
|
||||
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_AMP = Pattern.compile("&");
|
||||
private static final Pattern P_QUOTE = Pattern.compile("\"");
|
||||
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
|
||||
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
|
||||
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
|
||||
|
||||
// @xxx could grow large... maybe use sesat's ReferenceMap
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new SafeConcurrentHashMap<>();
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new SafeConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* set of allowed html elements, along with allowed attributes for each element
|
||||
**/
|
||||
private final Map<String, List<String>> vAllowed;
|
||||
/**
|
||||
* counts of open tags for each (allowable) html element
|
||||
**/
|
||||
private final Map<String, Integer> vTagCounts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* html elements which must always be self-closing (e.g. "<img />")
|
||||
**/
|
||||
private final String[] vSelfClosingTags;
|
||||
/**
|
||||
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
|
||||
**/
|
||||
private final String[] vNeedClosingTags;
|
||||
/**
|
||||
* set of disallowed html elements
|
||||
**/
|
||||
private final String[] vDisallowed;
|
||||
/**
|
||||
* attributes which should be checked for valid protocols
|
||||
**/
|
||||
private final String[] vProtocolAtts;
|
||||
/**
|
||||
* allowed protocols
|
||||
**/
|
||||
private final String[] vAllowedProtocols;
|
||||
/**
|
||||
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
|
||||
**/
|
||||
private final String[] vRemoveBlanks;
|
||||
/**
|
||||
* entities allowed within html markup
|
||||
**/
|
||||
private final String[] vAllowedEntities;
|
||||
/**
|
||||
* flag determining whether comments are allowed in input String.
|
||||
*/
|
||||
private final boolean stripComment;
|
||||
private final boolean encodeQuotes;
|
||||
private boolean vDebug = false;
|
||||
/**
|
||||
* flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>" becomes "<b> text </g>").
|
||||
* If set to false, unbalanced angle brackets will be
|
||||
* html escaped.
|
||||
*/
|
||||
private final boolean alwaysMakeTags;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public HTMLFilter() {
|
||||
vAllowed = new HashMap<>();
|
||||
|
||||
final ArrayList<String> a_atts = new ArrayList<>();
|
||||
a_atts.add("href");
|
||||
a_atts.add("target");
|
||||
vAllowed.put("a", a_atts);
|
||||
|
||||
final ArrayList<String> img_atts = new ArrayList<>();
|
||||
img_atts.add("src");
|
||||
img_atts.add("width");
|
||||
img_atts.add("height");
|
||||
img_atts.add("alt");
|
||||
vAllowed.put("img", img_atts);
|
||||
|
||||
final ArrayList<String> no_atts = new ArrayList<>();
|
||||
vAllowed.put("b", no_atts);
|
||||
vAllowed.put("strong", no_atts);
|
||||
vAllowed.put("i", no_atts);
|
||||
vAllowed.put("em", no_atts);
|
||||
|
||||
vSelfClosingTags = new String[]{"img"};
|
||||
vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
|
||||
vDisallowed = new String[]{};
|
||||
vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
|
||||
vProtocolAtts = new String[]{"src", "href"};
|
||||
vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
|
||||
vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
|
||||
stripComment = true;
|
||||
encodeQuotes = true;
|
||||
alwaysMakeTags = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set debug flag to true. Otherwise use default settings. See the default constructor.
|
||||
*
|
||||
* @param debug turn debug on with a true argument
|
||||
*/
|
||||
public HTMLFilter(final boolean debug) {
|
||||
this();
|
||||
vDebug = debug;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Map-parameter configurable constructor.
|
||||
*
|
||||
* @param conf map containing configuration. keys match field names.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public HTMLFilter(final Map<String, Object> conf) {
|
||||
|
||||
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
|
||||
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
|
||||
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
|
||||
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
|
||||
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
|
||||
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
|
||||
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
|
||||
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
|
||||
|
||||
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
|
||||
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
|
||||
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
|
||||
vDisallowed = (String[]) conf.get("vDisallowed");
|
||||
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
|
||||
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
|
||||
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
|
||||
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
|
||||
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
|
||||
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
|
||||
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
vTagCounts.clear();
|
||||
}
|
||||
|
||||
private void debug(final String msg) {
|
||||
if (vDebug) {
|
||||
Console.log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// my versions of some PHP library functions
|
||||
public static String chr(final int decimal) {
|
||||
return String.valueOf((char) decimal);
|
||||
}
|
||||
|
||||
public static String htmlSpecialChars(final String s) {
|
||||
String result = s;
|
||||
result = regexReplace(P_AMP, "&", result);
|
||||
result = regexReplace(P_QUOTE, """, result);
|
||||
result = regexReplace(P_LEFT_ARROW, "<", result);
|
||||
result = regexReplace(P_RIGHT_ARROW, ">", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* given a user submitted input String, filter out any invalid or restricted html.
|
||||
*
|
||||
* @param input text (i.e. submitted by a user) than may contain html
|
||||
* @return "clean" version of input, with only valid, whitelisted html elements allowed
|
||||
*/
|
||||
public String filter(final String input) {
|
||||
reset();
|
||||
String s = input;
|
||||
|
||||
debug("************************************************");
|
||||
debug(" INPUT: " + input);
|
||||
|
||||
s = escapeComments(s);
|
||||
debug(" escapeComments: " + s);
|
||||
|
||||
s = balanceHTML(s);
|
||||
debug(" balanceHTML: " + s);
|
||||
|
||||
s = checkTags(s);
|
||||
debug(" checkTags: " + s);
|
||||
|
||||
s = processRemoveBlanks(s);
|
||||
debug("processRemoveBlanks: " + s);
|
||||
|
||||
s = validateEntities(s);
|
||||
debug(" validateEntites: " + s);
|
||||
|
||||
debug("************************************************\n\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean isAlwaysMakeTags() {
|
||||
return alwaysMakeTags;
|
||||
}
|
||||
|
||||
public boolean isStripComments() {
|
||||
return stripComment;
|
||||
}
|
||||
|
||||
private String escapeComments(final String s) {
|
||||
final Matcher m = P_COMMENTS.matcher(s);
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
if (m.find()) {
|
||||
final String match = m.group(1); // (.*?)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String balanceHTML(String s) {
|
||||
if (alwaysMakeTags) {
|
||||
//
|
||||
// try and form html
|
||||
//
|
||||
s = regexReplace(P_END_ARROW, "", s);
|
||||
s = regexReplace(P_BODY_TO_END, "<$1>", s);
|
||||
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
|
||||
|
||||
} else {
|
||||
//
|
||||
// escape stray brackets
|
||||
//
|
||||
s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s);
|
||||
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s);
|
||||
|
||||
//
|
||||
// the last regexp causes '<>' entities to appear
|
||||
// (we need to do a lookahead assertion so that the last bracket can
|
||||
// be used in the next pass of the regexp)
|
||||
//
|
||||
s = regexReplace(P_BOTH_ARROWS, "", s);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String checkTags(String s) {
|
||||
Matcher m = P_TAGS.matcher(s);
|
||||
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
while (m.find()) {
|
||||
String replaceStr = m.group(1);
|
||||
replaceStr = processTag(replaceStr);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
// these get tallied in processTag
|
||||
// (remember to reset before subsequent calls to filter method)
|
||||
final StringBuilder sBuilder = new StringBuilder(buf.toString());
|
||||
for (String key : vTagCounts.keySet()) {
|
||||
for (int ii = 0; ii < vTagCounts.get(key); ii++) {
|
||||
sBuilder.append("</").append(key).append(">");
|
||||
}
|
||||
}
|
||||
s = sBuilder.toString();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String processRemoveBlanks(final String s) {
|
||||
String result = s;
|
||||
for (String tag : vRemoveBlanks) {
|
||||
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {
|
||||
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
|
||||
if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {
|
||||
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
|
||||
Matcher m = regex_pattern.matcher(s);
|
||||
return m.replaceAll(replacement);
|
||||
}
|
||||
|
||||
private String processTag(final String s) {
|
||||
// ending tags
|
||||
Matcher m = P_END_TAG.matcher(s);
|
||||
if (m.find()) {
|
||||
final String name = m.group(1).toLowerCase();
|
||||
if (allowed(name)) {
|
||||
if (!inArray(name, vSelfClosingTags)) {
|
||||
if (vTagCounts.containsKey(name)) {
|
||||
vTagCounts.put(name, vTagCounts.get(name) - 1);
|
||||
return "</" + name + ">";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// starting tags
|
||||
m = P_START_TAG.matcher(s);
|
||||
if (m.find()) {
|
||||
final String name = m.group(1).toLowerCase();
|
||||
final String body = m.group(2);
|
||||
String ending = m.group(3);
|
||||
|
||||
// debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
|
||||
if (allowed(name)) {
|
||||
final StringBuilder params = new StringBuilder();
|
||||
|
||||
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
|
||||
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
|
||||
final List<String> paramNames = new ArrayList<>();
|
||||
final List<String> paramValues = new ArrayList<>();
|
||||
while (m2.find()) {
|
||||
paramNames.add(m2.group(1)); // ([a-z0-9]+)
|
||||
paramValues.add(m2.group(3)); // (.*?)
|
||||
}
|
||||
while (m3.find()) {
|
||||
paramNames.add(m3.group(1)); // ([a-z0-9]+)
|
||||
paramValues.add(m3.group(3)); // ([^\"\\s']+)
|
||||
}
|
||||
|
||||
String paramName, paramValue;
|
||||
for (int ii = 0; ii < paramNames.size(); ii++) {
|
||||
paramName = paramNames.get(ii).toLowerCase();
|
||||
paramValue = paramValues.get(ii);
|
||||
|
||||
// debug( "paramName='" + paramName + "'" );
|
||||
// debug( "paramValue='" + paramValue + "'" );
|
||||
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
|
||||
|
||||
if (allowedAttribute(name, paramName)) {
|
||||
if (inArray(paramName, vProtocolAtts)) {
|
||||
paramValue = processParamProtocol(paramValue);
|
||||
}
|
||||
params.append(CharUtil.SPACE).append(paramName).append("=\"").append(paramValue).append("\"");
|
||||
}
|
||||
}
|
||||
|
||||
if (inArray(name, vSelfClosingTags)) {
|
||||
ending = " /";
|
||||
}
|
||||
|
||||
if (inArray(name, vNeedClosingTags)) {
|
||||
ending = "";
|
||||
}
|
||||
|
||||
if (ending == null || ending.length() < 1) {
|
||||
if (vTagCounts.containsKey(name)) {
|
||||
vTagCounts.put(name, vTagCounts.get(name) + 1);
|
||||
} else {
|
||||
vTagCounts.put(name, 1);
|
||||
}
|
||||
} else {
|
||||
ending = " /";
|
||||
}
|
||||
return "<" + name + params + ending + ">";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// comments
|
||||
m = P_COMMENT.matcher(s);
|
||||
if (!stripComment && m.find()) {
|
||||
return "<" + m.group() + ">";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private String processParamProtocol(String s) {
|
||||
s = decodeEntities(s);
|
||||
final Matcher m = P_PROTOCOL.matcher(s);
|
||||
if (m.find()) {
|
||||
final String protocol = m.group(1);
|
||||
if (!inArray(protocol, vAllowedProtocols)) {
|
||||
// bad protocol, turn into local anchor link instead
|
||||
s = "#" + s.substring(protocol.length() + 1);
|
||||
if (s.startsWith("#//")) {
|
||||
s = "#" + s.substring(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String decodeEntities(String s) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
Matcher m = P_ENTITY.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.decode(match);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENTITY_UNICODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.parseInt(match, 16);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENCODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.parseInt(match, 16);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
s = validateEntities(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
private String validateEntities(final String s) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
// validate entities throughout the string
|
||||
Matcher m = P_VALID_ENTITIES.matcher(s);
|
||||
while (m.find()) {
|
||||
final String one = m.group(1); // ([^&;]*)
|
||||
final String two = m.group(2); // (?=(;|&|$))
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return encodeQuotes(buf.toString());
|
||||
}
|
||||
|
||||
private String encodeQuotes(final String s) {
|
||||
if (encodeQuotes) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
Matcher m = P_VALID_QUOTES.matcher(s);
|
||||
while (m.find()) {
|
||||
final String one = m.group(1); // (>|^)
|
||||
final String two = m.group(2); // ([^<]+?)
|
||||
final String three = m.group(3); // (<|$)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
return buf.toString();
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
private String checkEntity(final String preamble, final String term) {
|
||||
|
||||
return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble;
|
||||
}
|
||||
|
||||
private boolean isValidEntity(final String entity) {
|
||||
return inArray(entity, vAllowedEntities);
|
||||
}
|
||||
|
||||
private static boolean inArray(final String s, final String[] array) {
|
||||
for (String item : array) {
|
||||
if (item != null && item.equals(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean allowed(final String name) {
|
||||
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
|
||||
}
|
||||
|
||||
private boolean allowedAttribute(final String name, final String paramName) {
|
||||
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
/**
|
||||
* Http 头域
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public enum Header {
|
||||
|
||||
//------------------------------------------------------------- 通用头域
|
||||
/**
|
||||
* 提供验证头,例如:
|
||||
* <pre>
|
||||
* Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
|
||||
* </pre>
|
||||
*/
|
||||
AUTHORIZATION("Authorization"),
|
||||
/**
|
||||
* 提供给代理服务器的用于身份验证的凭证,例如:
|
||||
* <pre>
|
||||
* Proxy-Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
|
||||
* </pre>
|
||||
*/
|
||||
PROXY_AUTHORIZATION("Proxy-Authorization"),
|
||||
/**
|
||||
* 提供日期和时间标志,说明报文是什么时间创建的
|
||||
*/
|
||||
DATE("Date"),
|
||||
/**
|
||||
* 允许客户端和服务器指定与请求/响应连接有关的选项
|
||||
*/
|
||||
CONNECTION("Connection"),
|
||||
/**
|
||||
* 给出发送端使用的MIME版本
|
||||
*/
|
||||
MIME_VERSION("MIME-Version"),
|
||||
/**
|
||||
* 如果报文采用了分块传输编码(chunked transfer encoding) 方式,就可以用这个首部列出位于报文拖挂(trailer)部分的首部集合
|
||||
*/
|
||||
TRAILER("Trailer"),
|
||||
/**
|
||||
* 告知接收端为了保证报文的可靠传输,对报文采用了什么编码方式
|
||||
*/
|
||||
TRANSFER_ENCODING("Transfer-Encoding"),
|
||||
/**
|
||||
* 给出了发送端可能想要"升级"使用的新版本和协议
|
||||
*/
|
||||
UPGRADE("Upgrade"),
|
||||
/**
|
||||
* 显示了报文经过的中间节点
|
||||
*/
|
||||
VIA("Via"),
|
||||
/**
|
||||
* 指定请求和响应遵循的缓存机制
|
||||
*/
|
||||
CACHE_CONTROL("Cache-Control"),
|
||||
/**
|
||||
* 用来包含实现特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1协议中,它的含义和Cache- Control:no-cache相同
|
||||
*/
|
||||
PRAGMA("Pragma"),
|
||||
/**
|
||||
* 请求表示提交内容类型或返回返回内容的MIME类型
|
||||
*/
|
||||
CONTENT_TYPE("Content-Type"),
|
||||
|
||||
//------------------------------------------------------------- 请求头域
|
||||
/**
|
||||
* 指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回
|
||||
*/
|
||||
HOST("Host"),
|
||||
/**
|
||||
* 允许客户端指定请求uri的源资源地址,这可以允许服务器生成回退链表,可用来登陆、优化cache等。他也允许废除的或错误的连接由于维护的目的被 追踪。如果请求的uri没有自己的uri地址,Referer不能被发送。如果指定的是部分uri地址,则此地址应该是一个相对地址
|
||||
*/
|
||||
REFERER("Referer"),
|
||||
/**
|
||||
* 指定请求的域
|
||||
*/
|
||||
ORIGIN("Origin"),
|
||||
/**
|
||||
* HTTP客户端运行的浏览器类型的详细信息。通过该头部信息,web服务器可以判断到当前HTTP请求的客户端浏览器类别
|
||||
*/
|
||||
USER_AGENT("User-Agent"),
|
||||
/**
|
||||
* 指定客户端能够接收的内容类型,内容类型中的先后次序表示客户端接收的先后次序
|
||||
*/
|
||||
ACCEPT("Accept"),
|
||||
/**
|
||||
* 指定HTTP客户端浏览器用来展示返回信息所优先选择的语言
|
||||
*/
|
||||
ACCEPT_LANGUAGE("Accept-Language"),
|
||||
/**
|
||||
* 指定客户端浏览器可以支持的web服务器返回内容压缩编码类型
|
||||
*/
|
||||
ACCEPT_ENCODING("Accept-Encoding"),
|
||||
/**
|
||||
* 浏览器可以接受的字符编码集
|
||||
*/
|
||||
ACCEPT_CHARSET("Accept-Charset"),
|
||||
/**
|
||||
* HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器
|
||||
*/
|
||||
COOKIE("Cookie"),
|
||||
/**
|
||||
* 请求的内容长度
|
||||
*/
|
||||
CONTENT_LENGTH("Content-Length"),
|
||||
|
||||
//------------------------------------------------------------- 响应头域
|
||||
/**
|
||||
* 提供WWW验证响应头
|
||||
*/
|
||||
WWW_AUTHENTICATE("WWW-Authenticate"),
|
||||
/**
|
||||
* Cookie
|
||||
*/
|
||||
SET_COOKIE("Set-Cookie"),
|
||||
/**
|
||||
* Content-Encoding
|
||||
*/
|
||||
CONTENT_ENCODING("Content-Encoding"),
|
||||
/**
|
||||
* Content-Disposition
|
||||
*/
|
||||
CONTENT_DISPOSITION("Content-Disposition"),
|
||||
/**
|
||||
* ETag
|
||||
*/
|
||||
ETAG("ETag"),
|
||||
/**
|
||||
* 重定向指示到的URL
|
||||
*/
|
||||
LOCATION("Location");
|
||||
|
||||
private final String value;
|
||||
|
||||
Header(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取值
|
||||
*
|
||||
* @return 值
|
||||
*/
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getValue();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.EscapeUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ReUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* HTML工具类
|
||||
*
|
||||
* <p>
|
||||
* 比如我们在使用爬虫爬取HTML页面后,需要对返回页面的HTML内容做一定处理,<br>
|
||||
* 比如去掉指定标签(例如广告栏等)、去除JS、去掉样式等等,这些操作都可以使用此工具类完成。
|
||||
*
|
||||
* @author xiaoleilu
|
||||
*/
|
||||
public class HtmlUtil {
|
||||
|
||||
public static final String NBSP = StrUtil.HTML_NBSP;
|
||||
public static final String AMP = StrUtil.HTML_AMP;
|
||||
public static final String QUOTE = StrUtil.HTML_QUOTE;
|
||||
public static final String APOS = StrUtil.HTML_APOS;
|
||||
public static final String LT = StrUtil.HTML_LT;
|
||||
public static final String GT = StrUtil.HTML_GT;
|
||||
|
||||
public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
|
||||
public static final String RE_SCRIPT = "<[\\s]*?script[^>]*?>.*?<[\\s]*?\\/[\\s]*?script[\\s]*?>";
|
||||
|
||||
private static final char[][] TEXT = new char[256][];
|
||||
|
||||
static {
|
||||
// ascii码值最大的是【0x7f=127】,扩展ascii码值最大的是【0xFF=255】,因为ASCII码使用指定的7位或8位二进制数组合来表示128或256种可能的字符,标准ASCII码也叫基础ASCII码。
|
||||
for (int i = 0; i < 256; i++) {
|
||||
TEXT[i] = new char[]{(char) i};
|
||||
}
|
||||
|
||||
// special HTML characters
|
||||
TEXT['\''] = "'".toCharArray(); // 单引号 (''' doesn't work - it is not by the w3 specs)
|
||||
TEXT['"'] = QUOTE.toCharArray(); // 双引号
|
||||
TEXT['&'] = AMP.toCharArray(); // &符
|
||||
TEXT['<'] = LT.toCharArray(); // 小于号
|
||||
TEXT['>'] = GT.toCharArray(); // 大于号
|
||||
TEXT[' '] = NBSP.toCharArray(); // 不断开空格(non-breaking space,缩写nbsp。ASCII值是32:是用键盘输入的空格;ASCII值是160:不间断空格,即  ,所产生的空格,作用是在页面换行时不被打断)
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义文本中的HTML字符为安全的字符,以下字符被转义:
|
||||
* <ul>
|
||||
* <li>' 替换为 &#039; (&apos; doesn't work in HTML4)</li>
|
||||
* <li>" 替换为 &quot;</li>
|
||||
* <li>& 替换为 &amp;</li>
|
||||
* <li>< 替换为 &lt;</li>
|
||||
* <li>> 替换为 &gt;</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param text 被转义的文本
|
||||
* @return 转义后的文本
|
||||
*/
|
||||
public static String escape(String text) {
|
||||
return encode(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 还原被转义的HTML特殊字符
|
||||
*
|
||||
* @param htmlStr 包含转义符的HTML内容
|
||||
* @return 转换后的字符串
|
||||
*/
|
||||
public static String unescape(String htmlStr) {
|
||||
if (StrUtil.isBlank(htmlStr)) {
|
||||
return htmlStr;
|
||||
}
|
||||
|
||||
return EscapeUtil.unescapeHtml4(htmlStr);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- encode text
|
||||
|
||||
/**
|
||||
* 清除所有HTML标签,但是不删除标签内的内容
|
||||
*
|
||||
* @param content 文本
|
||||
* @return 清除标签后的文本
|
||||
*/
|
||||
public static String cleanHtmlTag(String content) {
|
||||
return content.replaceAll(RE_HTML_MARK, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定HTML标签和被标签包围的内容<br>
|
||||
* 不区分大小写
|
||||
*
|
||||
* @param content 文本
|
||||
* @param tagNames 要清除的标签
|
||||
* @return 去除标签后的文本
|
||||
*/
|
||||
public static String removeHtmlTag(String content, String... tagNames) {
|
||||
return removeHtmlTag(content, true, tagNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定HTML标签,不包括内容<br>
|
||||
* 不区分大小写
|
||||
*
|
||||
* @param content 文本
|
||||
* @param tagNames 要清除的标签
|
||||
* @return 去除标签后的文本
|
||||
*/
|
||||
public static String unwrapHtmlTag(String content, String... tagNames) {
|
||||
return removeHtmlTag(content, false, tagNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定HTML标签<br>
|
||||
* 不区分大小写
|
||||
*
|
||||
* @param content 文本
|
||||
* @param withTagContent 是否去掉被包含在标签中的内容
|
||||
* @param tagNames 要清除的标签
|
||||
* @return 去除标签后的文本
|
||||
*/
|
||||
public static String removeHtmlTag(String content, boolean withTagContent, String... tagNames) {
|
||||
String regex;
|
||||
for (String tagName : tagNames) {
|
||||
if (StrUtil.isBlank(tagName)) {
|
||||
continue;
|
||||
}
|
||||
tagName = tagName.trim();
|
||||
// (?i)表示其后面的表达式忽略大小写
|
||||
if (withTagContent) {
|
||||
// 标签及其包含内容
|
||||
regex = StrUtil.format("(?i)<{}(\\s+[^>]*?)?/?>(.*?</{}>)?", tagName, tagName);
|
||||
} else {
|
||||
// 标签不包含内容
|
||||
regex = StrUtil.format("(?i)<{}(\\s+[^>]*?)?/?>|</?{}>", tagName, tagName);
|
||||
}
|
||||
|
||||
content = ReUtil.delAll(regex, content); // 非自闭标签小写
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除HTML标签中的属性,如果多个标签有相同属性,都去除
|
||||
*
|
||||
* @param content 文本
|
||||
* @param attrs 属性名(不区分大小写)
|
||||
* @return 处理后的文本
|
||||
*/
|
||||
public static String removeHtmlAttr(String content, String... attrs) {
|
||||
String regex;
|
||||
for (String attr : attrs) {
|
||||
// (?i) 表示忽略大小写
|
||||
// \s* 属性名前后的空白符去除
|
||||
// [^>]+? 属性值,至少有一个非>的字符,>表示标签结束
|
||||
// \s+(?=>) 表示属性值后跟空格加>,即末尾的属性,此时去掉空格
|
||||
// (?=\s|>) 表示属性值后跟空格(属性后还有别的属性)或者跟>(最后一个属性)
|
||||
regex = StrUtil.format("(?i)(\\s*{}\\s*=[^>]+?\\s+(?=>))|(\\s*{}\\s*=[^>]+?(?=\\s|>))", attr, attr);
|
||||
content = content.replaceAll(regex, StrUtil.EMPTY);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除指定标签的所有属性
|
||||
*
|
||||
* @param content 内容
|
||||
* @param tagNames 指定标签
|
||||
* @return 处理后的文本
|
||||
*/
|
||||
public static String removeAllHtmlAttr(String content, String... tagNames) {
|
||||
String regex;
|
||||
for (String tagName : tagNames) {
|
||||
regex = StrUtil.format("(?i)<{}[^>]*?>", tagName);
|
||||
content = content.replaceAll(regex, StrUtil.format("<{}>", tagName));
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder
|
||||
*
|
||||
* @param text 被编码的文本
|
||||
* @return 编码后的字符
|
||||
*/
|
||||
private static String encode(String text) {
|
||||
int len;
|
||||
if ((text == null) || ((len = text.length()) == 0)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
StringBuilder buffer = new StringBuilder(len + (len >> 2));
|
||||
char c;
|
||||
for (int i = 0; i < len; i++) {
|
||||
c = text.charAt(i);
|
||||
if (c < 256) {
|
||||
buffer.append(TEXT[c]);
|
||||
} else {
|
||||
buffer.append(c);
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤HTML文本,防止XSS攻击
|
||||
*
|
||||
* @param htmlContent HTML内容
|
||||
* @return 过滤后的内容
|
||||
*/
|
||||
public static String filter(String htmlContent) {
|
||||
return new HTMLFilter().filter(htmlContent);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollectionUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.map.CaseInsensitiveMap;
|
||||
import aiyh.utils.tool.cn.hutool.core.map.MapUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.CharsetUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* http基类
|
||||
*
|
||||
* @param <T> 子类类型,方便链式编程
|
||||
* @author Looly
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class HttpBase<T> {
|
||||
|
||||
/**
|
||||
* 默认的请求编码、URL的encode、decode编码
|
||||
*/
|
||||
protected static final Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8;
|
||||
|
||||
/**
|
||||
* HTTP/1.0
|
||||
*/
|
||||
public static final String HTTP_1_0 = "HTTP/1.0";
|
||||
/**
|
||||
* HTTP/1.1
|
||||
*/
|
||||
public static final String HTTP_1_1 = "HTTP/1.1";
|
||||
|
||||
/**
|
||||
* 存储头信息
|
||||
*/
|
||||
protected Map<String, List<String>> headers = new HashMap<>();
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
protected Charset charset = DEFAULT_CHARSET;
|
||||
/**
|
||||
* http版本
|
||||
*/
|
||||
protected String httpVersion = HTTP_1_1;
|
||||
/**
|
||||
* 存储主体
|
||||
*/
|
||||
protected byte[] bodyBytes;
|
||||
|
||||
// ---------------------------------------------------------------- Headers start
|
||||
|
||||
/**
|
||||
* 根据name获取头信息<br>
|
||||
* 根据RFC2616规范,header的name不区分大小写
|
||||
*
|
||||
* @param name Header名
|
||||
* @return Header值
|
||||
*/
|
||||
public String header(String name) {
|
||||
final List<String> values = headerList(name);
|
||||
if (CollectionUtil.isEmpty(values)) {
|
||||
return null;
|
||||
}
|
||||
return values.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据name获取头信息列表
|
||||
*
|
||||
* @param name Header名
|
||||
* @return Header值
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public List<String> headerList(String name) {
|
||||
if (StrUtil.isBlank(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final CaseInsensitiveMap<String, List<String>> headersIgnoreCase = new CaseInsensitiveMap<>(this.headers);
|
||||
return headersIgnoreCase.get(name.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据name获取头信息
|
||||
*
|
||||
* @param name Header名
|
||||
* @return Header值
|
||||
*/
|
||||
public String header(Header name) {
|
||||
if (null == name) {
|
||||
return null;
|
||||
}
|
||||
return header(name.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个header<br>
|
||||
* 如果覆盖模式,则替换之前的值,否则加入到值列表中
|
||||
*
|
||||
* @param name Header名
|
||||
* @param value Header值
|
||||
* @param isOverride 是否覆盖已有值
|
||||
* @return T 本身
|
||||
*/
|
||||
public T header(String name, String value, boolean isOverride) {
|
||||
if (null != name && null != value) {
|
||||
final List<String> values = headers.get(name.trim());
|
||||
if (isOverride || CollectionUtil.isEmpty(values)) {
|
||||
final ArrayList<String> valueList = new ArrayList<>();
|
||||
valueList.add(value);
|
||||
headers.put(name.trim(), valueList);
|
||||
} else {
|
||||
values.add(value.trim());
|
||||
}
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个header<br>
|
||||
* 如果覆盖模式,则替换之前的值,否则加入到值列表中
|
||||
*
|
||||
* @param name Header名
|
||||
* @param value Header值
|
||||
* @param isOverride 是否覆盖已有值
|
||||
* @return T 本身
|
||||
*/
|
||||
public T header(Header name, String value, boolean isOverride) {
|
||||
return header(name.toString(), value, isOverride);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个header<br>
|
||||
* 覆盖模式,则替换之前的值
|
||||
*
|
||||
* @param name Header名
|
||||
* @param value Header值
|
||||
* @return T 本身
|
||||
*/
|
||||
public T header(Header name, String value) {
|
||||
return header(name.toString(), value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个header<br>
|
||||
* 覆盖模式,则替换之前的值
|
||||
*
|
||||
* @param name Header名
|
||||
* @param value Header值
|
||||
* @return T 本身
|
||||
*/
|
||||
public T header(String name, String value) {
|
||||
return header(name, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求头
|
||||
*
|
||||
* @param headers 请求头
|
||||
* @param isOverride 是否覆盖已有头信息
|
||||
* @return this
|
||||
* @since 4.6.3
|
||||
*/
|
||||
public T headerMap(Map<String, String> headers, boolean isOverride) {
|
||||
if (MapUtil.isEmpty(headers)) {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
for (Entry<String, String> entry : headers.entrySet()) {
|
||||
this.header(entry.getKey(), StrUtil.nullToEmpty(entry.getValue()), isOverride);
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求头<br>
|
||||
* 不覆盖原有请求头
|
||||
*
|
||||
* @param headers 请求头
|
||||
* @return this
|
||||
*/
|
||||
public T header(Map<String, List<String>> headers) {
|
||||
return header(headers, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求头
|
||||
*
|
||||
* @param headers 请求头
|
||||
* @param isOverride 是否覆盖已有头信息
|
||||
* @return this
|
||||
* @since 4.0.8
|
||||
*/
|
||||
public T header(Map<String, List<String>> headers, boolean isOverride) {
|
||||
if (MapUtil.isEmpty(headers)) {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
String name;
|
||||
for (Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
name = entry.getKey();
|
||||
for (String value : entry.getValue()) {
|
||||
this.header(name, StrUtil.nullToEmpty(value), isOverride);
|
||||
}
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增请求头<br>
|
||||
* 不覆盖原有请求头
|
||||
*
|
||||
* @param headers 请求头
|
||||
* @return this
|
||||
* @since 4.0.3
|
||||
*/
|
||||
public T addHeaders(Map<String, String> headers) {
|
||||
if (MapUtil.isEmpty(headers)) {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
for (Entry<String, String> entry : headers.entrySet()) {
|
||||
this.header(entry.getKey(), StrUtil.nullToEmpty(entry.getValue()), false);
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个头信息
|
||||
*
|
||||
* @param name Header名
|
||||
* @return this
|
||||
*/
|
||||
public T removeHeader(String name) {
|
||||
if (name != null) {
|
||||
headers.remove(name.trim());
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个头信息
|
||||
*
|
||||
* @param name Header名
|
||||
* @return this
|
||||
*/
|
||||
public T removeHeader(Header name) {
|
||||
return removeHeader(name.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取headers
|
||||
*
|
||||
* @return Headers Map
|
||||
*/
|
||||
public Map<String, List<String>> headers() {
|
||||
return Collections.unmodifiableMap(headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有头信息,包括全局头信息
|
||||
*
|
||||
* @return this
|
||||
* @since 5.7.13
|
||||
*/
|
||||
public T clearHeaders() {
|
||||
this.headers.clear();
|
||||
return (T) this;
|
||||
}
|
||||
// ---------------------------------------------------------------- Headers end
|
||||
|
||||
/**
|
||||
* 返回http版本
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String httpVersion() {
|
||||
return httpVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置http版本,此方法不会影响到实际请求的HTTP版本,只用于帮助判断是否connect:Keep-Alive
|
||||
*
|
||||
* @param httpVersion Http版本,{@link HttpBase#HTTP_1_0},{@link HttpBase#HTTP_1_1}
|
||||
* @return this
|
||||
*/
|
||||
public T httpVersion(String httpVersion) {
|
||||
this.httpVersion = httpVersion;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取bodyBytes存储字节码
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] bodyBytes() {
|
||||
return this.bodyBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回字符集
|
||||
*
|
||||
* @return 字符集
|
||||
*/
|
||||
public String charset() {
|
||||
return charset.name();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字符集
|
||||
*
|
||||
* @param charset 字符集
|
||||
* @return T 自己
|
||||
* @see CharsetUtil
|
||||
*/
|
||||
public T charset(String charset) {
|
||||
if (StrUtil.isNotBlank(charset)) {
|
||||
charset(Charset.forName(charset));
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字符集
|
||||
*
|
||||
* @param charset 字符集
|
||||
* @return T 自己
|
||||
* @see CharsetUtil
|
||||
*/
|
||||
public T charset(Charset charset) {
|
||||
if (null != charset) {
|
||||
this.charset = charset;
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = StrUtil.builder();
|
||||
sb.append("Request Headers: ").append(StrUtil.CRLF);
|
||||
for (Entry<String, List<String>> entry : this.headers.entrySet()) {
|
||||
sb.append(" ").append(
|
||||
entry.getKey()).append(": ").append(CollUtil.join(entry.getValue(), ","))
|
||||
.append(StrUtil.CRLF);
|
||||
}
|
||||
|
||||
sb.append("Request Body: ").append(StrUtil.CRLF);
|
||||
sb.append(" ").append(StrUtil.str(this.bodyBytes, this.charset)).append(StrUtil.CRLF);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,300 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
|
||||
import aiyh.utils.tool.cn.hutool.core.net.SSLUtil;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
|
||||
/**
|
||||
* Http配置项
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public class HttpConfig {
|
||||
|
||||
/**
|
||||
* 创建默认Http配置信息
|
||||
*
|
||||
* @return HttpConfig
|
||||
*/
|
||||
public static HttpConfig create() {
|
||||
return new HttpConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认连接超时
|
||||
*/
|
||||
int connectionTimeout = HttpGlobalConfig.getTimeout();
|
||||
/**
|
||||
* 默认读取超时
|
||||
*/
|
||||
int readTimeout = HttpGlobalConfig.getTimeout();
|
||||
|
||||
/**
|
||||
* 是否禁用缓存
|
||||
*/
|
||||
boolean isDisableCache;
|
||||
|
||||
/**
|
||||
* 最大重定向次数
|
||||
*/
|
||||
int maxRedirectCount = HttpGlobalConfig.getMaxRedirectCount();
|
||||
|
||||
/**
|
||||
* 代理
|
||||
*/
|
||||
Proxy proxy;
|
||||
|
||||
/**
|
||||
* HostnameVerifier,用于HTTPS安全连接
|
||||
*/
|
||||
HostnameVerifier hostnameVerifier;
|
||||
/**
|
||||
* SSLSocketFactory,用于HTTPS安全连接
|
||||
*/
|
||||
SSLSocketFactory ssf;
|
||||
|
||||
/**
|
||||
* Chuncked块大小,0或小于0表示不设置Chuncked模式
|
||||
*/
|
||||
int blockSize;
|
||||
|
||||
/**
|
||||
* 获取是否忽略响应读取时可能的EOF异常。<br>
|
||||
* 在Http协议中,对于Transfer-Encoding: Chunked在正常情况下末尾会写入一个Length为0的的chunk标识完整结束。<br>
|
||||
* 如果服务端未遵循这个规范或响应没有正常结束,会报EOF异常,此选项用于是否忽略这个异常。
|
||||
*/
|
||||
boolean ignoreEOFError = HttpGlobalConfig.isIgnoreEOFError();
|
||||
/**
|
||||
* 获取是否忽略解码URL,包括URL中的Path部分和Param部分。<br>
|
||||
* 在构建Http请求时,用户传入的URL可能有编码后和未编码的内容混合在一起,如果此参数为{@code true},则会统一解码编码后的参数,<br>
|
||||
* 按照RFC3986规范,在发送请求时,全部编码之。如果为{@code false},则不会解码已经编码的内容,在请求时只编码需要编码的部分。
|
||||
*/
|
||||
boolean decodeUrl = HttpGlobalConfig.isDecodeUrl();
|
||||
|
||||
/**
|
||||
* 请求前的拦截器,用于在请求前重新编辑请求
|
||||
*/
|
||||
final HttpInterceptor.Chain<aiyh.utils.tool.cn.hutool.http.HttpRequest> requestInterceptors = GlobalInterceptor.INSTANCE.getCopiedRequestInterceptor();
|
||||
/**
|
||||
* 响应后的拦截器,用于在响应后处理逻辑
|
||||
*/
|
||||
final HttpInterceptor.Chain<aiyh.utils.tool.cn.hutool.http.HttpResponse> responseInterceptors = GlobalInterceptor.INSTANCE.getCopiedResponseInterceptor();
|
||||
|
||||
/**
|
||||
* 重定向时是否使用拦截器
|
||||
*/
|
||||
boolean interceptorOnRedirect;
|
||||
|
||||
/**
|
||||
* 设置超时,单位:毫秒<br>
|
||||
* 超时包括:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 连接超时
|
||||
* 2. 读取响应超时
|
||||
* </pre>
|
||||
*
|
||||
* @param milliseconds 超时毫秒数
|
||||
* @return this
|
||||
* @see #setConnectionTimeout(int)
|
||||
* @see #setReadTimeout(int)
|
||||
*/
|
||||
public HttpConfig timeout(int milliseconds) {
|
||||
setConnectionTimeout(milliseconds);
|
||||
setReadTimeout(milliseconds);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置连接超时,单位:毫秒
|
||||
*
|
||||
* @param milliseconds 超时毫秒数
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setConnectionTimeout(int milliseconds) {
|
||||
this.connectionTimeout = milliseconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置连接超时,单位:毫秒
|
||||
*
|
||||
* @param milliseconds 超时毫秒数
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setReadTimeout(int milliseconds) {
|
||||
this.readTimeout = milliseconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用缓存
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig disableCache() {
|
||||
this.isDisableCache = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置最大重定向次数<br>
|
||||
* 如果次数小于1则表示不重定向,大于等于1表示打开重定向
|
||||
*
|
||||
* @param maxRedirectCount 最大重定向次数
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setMaxRedirectCount(int maxRedirectCount) {
|
||||
this.maxRedirectCount = Math.max(maxRedirectCount, 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置域名验证器<br>
|
||||
* 只针对HTTPS请求,如果不设置,不做验证,所有域名被信任
|
||||
*
|
||||
* @param hostnameVerifier HostnameVerifier
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setHostnameVerifier(HostnameVerifier hostnameVerifier) {
|
||||
// 验证域
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Http代理
|
||||
*
|
||||
* @param host 代理 主机
|
||||
* @param port 代理 端口
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setHttpProxy(String host, int port) {
|
||||
final Proxy proxy = new Proxy(Proxy.Type.HTTP,
|
||||
new InetSocketAddress(host, port));
|
||||
return setProxy(proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置代理
|
||||
*
|
||||
* @param proxy 代理 {@link Proxy}
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setProxy(Proxy proxy) {
|
||||
this.proxy = proxy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置SSLSocketFactory<br>
|
||||
* 只针对HTTPS请求,如果不设置,使用默认的SSLSocketFactory<br>
|
||||
* 默认SSLSocketFactory为:SSLSocketFactoryBuilder.create().build();
|
||||
*
|
||||
* @param ssf SSLScketFactory
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setSSLSocketFactory(SSLSocketFactory ssf) {
|
||||
this.ssf = ssf;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置HTTPS安全连接协议,只针对HTTPS请求,可以使用的协议包括:<br>
|
||||
* 此方法调用后{@link #setSSLSocketFactory(SSLSocketFactory)} 将被覆盖。
|
||||
*
|
||||
* <pre>
|
||||
* 1. TLSv1.2
|
||||
* 2. TLSv1.1
|
||||
* 3. SSLv3
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* @param protocol 协议
|
||||
* @return this
|
||||
* @see SSLUtil#createSSLContext(String)
|
||||
* @see #setSSLSocketFactory(SSLSocketFactory)
|
||||
*/
|
||||
public HttpConfig setSSLProtocol(String protocol) {
|
||||
Assert.notBlank(protocol, "protocol must be not blank!");
|
||||
setSSLSocketFactory(SSLUtil.createSSLContext(protocol).getSocketFactory());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 采用流方式上传数据,无需本地缓存数据。<br>
|
||||
* HttpUrlConnection默认是将所有数据读到本地缓存,然后再发送给服务器,这样上传大文件时就会导致内存溢出。
|
||||
*
|
||||
* @param blockSize 块大小(bytes数),0或小于0表示不设置Chuncked模式
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setBlockSize(int blockSize) {
|
||||
this.blockSize = blockSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否忽略响应读取时可能的EOF异常。<br>
|
||||
* 在Http协议中,对于Transfer-Encoding: Chunked在正常情况下末尾会写入一个Length为0的的chunk标识完整结束。<br>
|
||||
* 如果服务端未遵循这个规范或响应没有正常结束,会报EOF异常,此选项用于是否忽略这个异常。
|
||||
*
|
||||
* @param ignoreEOFError 是否忽略响应读取时可能的EOF异常。
|
||||
* @return this
|
||||
* @since 5.7.20
|
||||
*/
|
||||
public HttpConfig setIgnoreEOFError(boolean ignoreEOFError) {
|
||||
this.ignoreEOFError = ignoreEOFError;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否忽略解码URL,包括URL中的Path部分和Param部分。<br>
|
||||
* 在构建Http请求时,用户传入的URL可能有编码后和未编码的内容混合在一起,如果此参数为{@code true},则会统一解码编码后的参数,<br>
|
||||
* 按照RFC3986规范,在发送请求时,全部编码之。如果为{@code false},则不会解码已经编码的内容,在请求时只编码需要编码的部分。
|
||||
*
|
||||
* @param decodeUrl 是否忽略解码URL
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setDecodeUrl(boolean decodeUrl) {
|
||||
this.decodeUrl = decodeUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置拦截器,用于在请求前重新编辑请求
|
||||
*
|
||||
* @param interceptor 拦截器实现
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig addRequestInterceptor(HttpInterceptor<HttpRequest> interceptor) {
|
||||
this.requestInterceptors.addChain(interceptor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置拦截器,用于在请求前重新编辑请求
|
||||
*
|
||||
* @param interceptor 拦截器实现
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig addResponseInterceptor(HttpInterceptor<HttpResponse> interceptor) {
|
||||
this.responseInterceptors.addChain(interceptor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重定向时是否使用拦截器
|
||||
*
|
||||
* @param interceptorOnRedirect 重定向时是否使用拦截器
|
||||
* @return this
|
||||
*/
|
||||
public HttpConfig setInterceptorOnRedirect(boolean interceptorOnRedirect) {
|
||||
this.interceptorOnRedirect = interceptorOnRedirect;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,568 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.map.MapUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.URLUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.ssl.DefaultSSLInfo;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* http连接对象,对HttpURLConnection的包装
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class HttpConnection {
|
||||
|
||||
private final URL url;
|
||||
private final Proxy proxy;
|
||||
private HttpURLConnection conn;
|
||||
|
||||
/**
|
||||
* 创建HttpConnection
|
||||
*
|
||||
* @param urlStr URL
|
||||
* @param proxy 代理,无代理传{@code null}
|
||||
* @return HttpConnection
|
||||
*/
|
||||
public static HttpConnection create(String urlStr, Proxy proxy) {
|
||||
return create(URLUtil.toUrlForHttp(urlStr), proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建HttpConnection
|
||||
*
|
||||
* @param url URL
|
||||
* @param proxy 代理,无代理传{@code null}
|
||||
* @return HttpConnection
|
||||
*/
|
||||
public static HttpConnection create(URL url, Proxy proxy) {
|
||||
return new HttpConnection(url, proxy);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- Constructor start
|
||||
|
||||
/**
|
||||
* 构造HttpConnection
|
||||
*
|
||||
* @param url URL
|
||||
* @param proxy 代理
|
||||
*/
|
||||
public HttpConnection(URL url, Proxy proxy) {
|
||||
this.url = url;
|
||||
this.proxy = proxy;
|
||||
|
||||
// 初始化Http连接
|
||||
initConn();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- Constructor end
|
||||
|
||||
/**
|
||||
* 初始化连接相关信息
|
||||
*
|
||||
* @return HttpConnection
|
||||
* @since 4.4.1
|
||||
*/
|
||||
public HttpConnection initConn() {
|
||||
try {
|
||||
this.conn = openHttp();
|
||||
} catch (IOException e) {
|
||||
throw new HttpException(e);
|
||||
}
|
||||
|
||||
// 默认读取响应内容
|
||||
this.conn.setDoInput(true);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- Getters And Setters start
|
||||
|
||||
/**
|
||||
* 获取请求方法,GET/POST
|
||||
*
|
||||
* @return 请求方法, GET/POST
|
||||
*/
|
||||
public aiyh.utils.tool.cn.hutool.http.Method getMethod() {
|
||||
return aiyh.utils.tool.cn.hutool.http.Method.valueOf(this.conn.getRequestMethod());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求方法
|
||||
*
|
||||
* @param method 请求方法
|
||||
* @return 自己
|
||||
*/
|
||||
public HttpConnection setMethod(aiyh.utils.tool.cn.hutool.http.Method method) {
|
||||
if (aiyh.utils.tool.cn.hutool.http.Method.POST.equals(method) //
|
||||
|| aiyh.utils.tool.cn.hutool.http.Method.PUT.equals(method)//
|
||||
|| aiyh.utils.tool.cn.hutool.http.Method.PATCH.equals(method)//
|
||||
|| aiyh.utils.tool.cn.hutool.http.Method.DELETE.equals(method)) {
|
||||
this.conn.setUseCaches(false);
|
||||
|
||||
// 增加PATCH方法支持
|
||||
if (aiyh.utils.tool.cn.hutool.http.Method.PATCH.equals(method)) {
|
||||
try {
|
||||
HttpGlobalConfig.allowPatch();
|
||||
} catch (Exception ignore) {
|
||||
// ignore
|
||||
// https://github.com/dromara/hutool/issues/2832
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// method
|
||||
try {
|
||||
this.conn.setRequestMethod(method.toString());
|
||||
} catch (ProtocolException e) {
|
||||
if (aiyh.utils.tool.cn.hutool.http.Method.PATCH.equals(method)) {
|
||||
// 如果全局设置失效,此处针对单独链接重新设置
|
||||
reflectSetMethod(method);
|
||||
} else {
|
||||
throw new HttpException(e);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求URL
|
||||
*
|
||||
* @return 请求URL
|
||||
*/
|
||||
public URL getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得代理
|
||||
*
|
||||
* @return {@link Proxy}
|
||||
*/
|
||||
public Proxy getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取HttpURLConnection对象
|
||||
*
|
||||
* @return HttpURLConnection
|
||||
*/
|
||||
public HttpURLConnection getHttpURLConnection() {
|
||||
return conn;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- Getters And Setters end
|
||||
|
||||
// ---------------------------------------------------------------- Headers start
|
||||
|
||||
/**
|
||||
* 设置请求头<br>
|
||||
* 当请求头存在时,覆盖之
|
||||
*
|
||||
* @param header 头名
|
||||
* @param value 头值
|
||||
* @param isOverride 是否覆盖旧值
|
||||
* @return HttpConnection
|
||||
*/
|
||||
public HttpConnection header(String header, String value, boolean isOverride) {
|
||||
if (null != this.conn) {
|
||||
if (isOverride) {
|
||||
this.conn.setRequestProperty(header, value);
|
||||
} else {
|
||||
this.conn.addRequestProperty(header, value);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求头<br>
|
||||
* 当请求头存在时,覆盖之
|
||||
*
|
||||
* @param header 头名
|
||||
* @param value 头值
|
||||
* @param isOverride 是否覆盖旧值
|
||||
* @return HttpConnection
|
||||
*/
|
||||
public HttpConnection header(aiyh.utils.tool.cn.hutool.http.Header header, String value, boolean isOverride) {
|
||||
return header(header.toString(), value, isOverride);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求头<br>
|
||||
* 不覆盖原有请求头
|
||||
*
|
||||
* @param headerMap 请求头
|
||||
* @param isOverride 是否覆盖
|
||||
* @return this
|
||||
*/
|
||||
public HttpConnection header(Map<String, List<String>> headerMap, boolean isOverride) {
|
||||
if (MapUtil.isNotEmpty(headerMap)) {
|
||||
String name;
|
||||
for (Entry<String, List<String>> entry : headerMap.entrySet()) {
|
||||
name = entry.getKey();
|
||||
for (String value : entry.getValue()) {
|
||||
this.header(name, StrUtil.nullToEmpty(value), isOverride);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Http请求头
|
||||
*
|
||||
* @param name Header名
|
||||
* @return Http请求头值
|
||||
*/
|
||||
public String header(String name) {
|
||||
return this.conn.getHeaderField(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Http请求头
|
||||
*
|
||||
* @param name Header名
|
||||
* @return Http请求头值
|
||||
*/
|
||||
public String header(aiyh.utils.tool.cn.hutool.http.Header name) {
|
||||
return header(name.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有Http请求头
|
||||
*
|
||||
* @return Http请求头Map
|
||||
*/
|
||||
public Map<String, List<String>> headers() {
|
||||
return this.conn.getHeaderFields();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Headers end
|
||||
|
||||
/**
|
||||
* 设置https请求参数<br>
|
||||
* 有些时候htts请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现,此为sun内部api,按照普通http请求处理
|
||||
*
|
||||
* @param hostnameVerifier 域名验证器,非https传入null
|
||||
* @param ssf SSLSocketFactory,非https传入null
|
||||
* @return this
|
||||
* @throws HttpException KeyManagementException和NoSuchAlgorithmException异常包装
|
||||
*/
|
||||
public HttpConnection setHttpsInfo(HostnameVerifier hostnameVerifier, SSLSocketFactory ssf) throws HttpException {
|
||||
final HttpURLConnection conn = this.conn;
|
||||
|
||||
if (conn instanceof HttpsURLConnection) {
|
||||
// Https请求
|
||||
final HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
|
||||
// 验证域
|
||||
httpsConn.setHostnameVerifier(ObjectUtil.defaultIfNull(hostnameVerifier, DefaultSSLInfo.TRUST_ANY_HOSTNAME_VERIFIER));
|
||||
httpsConn.setSSLSocketFactory(ObjectUtil.defaultIfNull(ssf, DefaultSSLInfo.DEFAULT_SSF));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭缓存
|
||||
*
|
||||
* @return this
|
||||
* @see HttpURLConnection#setUseCaches(boolean)
|
||||
*/
|
||||
public HttpConnection disableCache() {
|
||||
this.conn.setUseCaches(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置连接超时
|
||||
*
|
||||
* @param timeout 超时
|
||||
* @return this
|
||||
*/
|
||||
public HttpConnection setConnectTimeout(int timeout) {
|
||||
if (timeout > 0 && null != this.conn) {
|
||||
this.conn.setConnectTimeout(timeout);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置读取超时
|
||||
*
|
||||
* @param timeout 超时
|
||||
* @return this
|
||||
*/
|
||||
public HttpConnection setReadTimeout(int timeout) {
|
||||
if (timeout > 0 && null != this.conn) {
|
||||
this.conn.setReadTimeout(timeout);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置连接和读取的超时时间
|
||||
*
|
||||
* @param timeout 超时时间
|
||||
* @return this
|
||||
*/
|
||||
public HttpConnection setConnectionAndReadTimeout(int timeout) {
|
||||
setConnectTimeout(timeout);
|
||||
setReadTimeout(timeout);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Cookie
|
||||
*
|
||||
* @param cookie Cookie
|
||||
* @return this
|
||||
*/
|
||||
public HttpConnection setCookie(String cookie) {
|
||||
if (cookie != null) {
|
||||
header(Header.COOKIE, cookie, true);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 采用流方式上传数据,无需本地缓存数据。<br>
|
||||
* HttpUrlConnection默认是将所有数据读到本地缓存,然后再发送给服务器,这样上传大文件时就会导致内存溢出。
|
||||
*
|
||||
* @param blockSize 块大小(bytes数),0或小于0表示不设置Chuncked模式
|
||||
* @return this
|
||||
*/
|
||||
public HttpConnection setChunkedStreamingMode(int blockSize) {
|
||||
if (blockSize > 0) {
|
||||
conn.setChunkedStreamingMode(blockSize);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置自动HTTP 30X跳转
|
||||
*
|
||||
* @param isInstanceFollowRedirects 是否自定跳转
|
||||
* @return this
|
||||
*/
|
||||
public HttpConnection setInstanceFollowRedirects(boolean isInstanceFollowRedirects) {
|
||||
conn.setInstanceFollowRedirects(isInstanceFollowRedirects);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接
|
||||
*
|
||||
* @return this
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public HttpConnection connect() throws IOException {
|
||||
if (null != this.conn) {
|
||||
this.conn.connect();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 静默断开连接。不抛出异常
|
||||
*
|
||||
* @return this
|
||||
* @since 4.6.0
|
||||
*/
|
||||
public HttpConnection disconnectQuietly() {
|
||||
try {
|
||||
disconnect();
|
||||
} catch (Throwable e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 断开连接
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public HttpConnection disconnect() {
|
||||
if (null != this.conn) {
|
||||
this.conn.disconnect();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得输入流对象<br>
|
||||
* 输入流对象用于读取数据
|
||||
*
|
||||
* @return 输入流对象
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (null != this.conn) {
|
||||
return this.conn.getInputStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当返回错误代码时,获得错误内容流
|
||||
*
|
||||
* @return 错误内容
|
||||
*/
|
||||
public InputStream getErrorStream() {
|
||||
if (null != this.conn) {
|
||||
return this.conn.getErrorStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输出流对象 输出流对象用于发送数据
|
||||
*
|
||||
* @return OutputStream
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
if (null == this.conn) {
|
||||
throw new IOException("HttpURLConnection has not been initialized.");
|
||||
}
|
||||
|
||||
final aiyh.utils.tool.cn.hutool.http.Method method = getMethod();
|
||||
|
||||
// 当有写出需求时,自动打开之
|
||||
this.conn.setDoOutput(true);
|
||||
final OutputStream out = this.conn.getOutputStream();
|
||||
|
||||
// 解决在Rest请求中,GET请求附带body导致GET请求被强制转换为POST
|
||||
// 在sun.net.www.protocol.http.HttpURLConnection.getOutputStream0方法中,会把GET方法
|
||||
// 修改为POST,而且无法调用setRequestMethod方法修改,因此此处使用反射强制修改字段属性值
|
||||
// https://stackoverflow.com/questions/978061/http-get-with-request-body/983458
|
||||
if (method == aiyh.utils.tool.cn.hutool.http.Method.GET && method != getMethod()) {
|
||||
reflectSetMethod(method);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应码
|
||||
*
|
||||
* @return 响应码
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public int responseCode() throws IOException {
|
||||
if (null != this.conn) {
|
||||
return this.conn.getResponseCode();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得字符集编码<br>
|
||||
* 从Http连接的头信息中获得字符集<br>
|
||||
* 从ContentType中获取
|
||||
*
|
||||
* @return 字符集编码
|
||||
*/
|
||||
public String getCharsetName() {
|
||||
return HttpUtil.getCharset(conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字符集编码<br>
|
||||
* 从Http连接的头信息中获得字符集<br>
|
||||
* 从ContentType中获取
|
||||
*
|
||||
* @return {@link Charset}编码
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public Charset getCharset() {
|
||||
Charset charset = null;
|
||||
final String charsetName = getCharsetName();
|
||||
if (StrUtil.isNotBlank(charsetName)) {
|
||||
try {
|
||||
charset = Charset.forName(charsetName);
|
||||
} catch (UnsupportedCharsetException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = StrUtil.builder();
|
||||
sb.append("Request URL: ").append(this.url).append(StrUtil.CRLF);
|
||||
sb.append("Request Method: ").append(this.getMethod()).append(StrUtil.CRLF);
|
||||
// sb.append("Request Headers: ").append(StrUtil.CRLF);
|
||||
// for (Entry<String, List<String>> entry : this.conn.getHeaderFields().entrySet()) {
|
||||
// sb.append(" ").append(entry).append(StrUtil.CRLF);
|
||||
// }
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- Private Method start
|
||||
|
||||
/**
|
||||
* 初始化http或https请求参数<br>
|
||||
* 有些时候https请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现,此为sun内部api,按照普通http请求处理
|
||||
*
|
||||
* @return {@link HttpURLConnection},https返回{@link HttpsURLConnection}
|
||||
*/
|
||||
private HttpURLConnection openHttp() throws IOException {
|
||||
final URLConnection conn = openConnection();
|
||||
if (!(conn instanceof HttpURLConnection)) {
|
||||
// 防止其它协议造成的转换异常
|
||||
throw new HttpException("'{}' of URL [{}] is not a http connection, make sure URL is format for http.", conn.getClass().getName(), this.url);
|
||||
}
|
||||
|
||||
return (HttpURLConnection) conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* 建立连接
|
||||
*
|
||||
* @return {@link URLConnection}
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private URLConnection openConnection() throws IOException {
|
||||
return (null == this.proxy) ? url.openConnection() : url.openConnection(this.proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过反射设置方法名,首先设置HttpURLConnection本身的方法名,再检查是否为代理类,如果是,设置带路对象的方法名。
|
||||
*
|
||||
* @param method 方法名
|
||||
*/
|
||||
private void reflectSetMethod(Method method) {
|
||||
ReflectUtil.setFieldValue(this.conn, "method", method.name());
|
||||
|
||||
// HttpsURLConnectionImpl实现中,使用了代理类,需要修改被代理类的method方法
|
||||
final Object delegate = ReflectUtil.getFieldValue(this.conn, "delegate");
|
||||
if (null != delegate) {
|
||||
ReflectUtil.setFieldValue(delegate, "method", method.name());
|
||||
}
|
||||
}
|
||||
// --------------------------------------------------------------- Private Method end
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.FastByteArrayOutputStream;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.StreamProgress;
|
||||
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 下载封装,下载统一使用{@code GET}请求,默认支持30x跳转
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.6.4
|
||||
*/
|
||||
public class HttpDownloader {
|
||||
|
||||
/**
|
||||
* 下载远程文本
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param customCharset 自定义的字符集,可以使用{@code CharsetUtil#charset} 方法转换
|
||||
* @param streamPress 进度条 {@link StreamProgress}
|
||||
* @return 文本
|
||||
*/
|
||||
public static String downloadString(String url, Charset customCharset, StreamProgress streamPress) {
|
||||
final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
|
||||
download(url, out, true, streamPress);
|
||||
return null == customCharset ? out.toString() : out.toString(customCharset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件数据,支持30x跳转
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @return 文件数据
|
||||
*/
|
||||
public static byte[] downloadBytes(String url) {
|
||||
return requestDownload(url, -1).bodyBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param targetFileOrDir 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @param streamProgress 进度条
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long downloadFile(String url, File targetFileOrDir, int timeout, StreamProgress streamProgress) {
|
||||
return requestDownload(url, timeout).writeBody(targetFileOrDir, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件-避免未完成的文件<br>
|
||||
* 来自:https://gitee.com/dromara/hutool/pulls/407<br>
|
||||
* 此方法原理是先在目标文件同级目录下创建临时文件,下载之,等下载完毕后重命名,避免因下载错误导致的文件不完整。
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param targetFileOrDir 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param tempFileSuffix 临时文件后缀,默认".temp"
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @param streamProgress 进度条
|
||||
* @return 下载大小
|
||||
* @since 5.7.12
|
||||
*/
|
||||
public long downloadFile(String url, File targetFileOrDir, String tempFileSuffix, int timeout, StreamProgress streamProgress) {
|
||||
return requestDownload(url, timeout).writeBody(targetFileOrDir, tempFileSuffix, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件,返回文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param targetFileOrDir 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @param streamProgress 进度条
|
||||
* @return 文件
|
||||
*/
|
||||
public static File downloadForFile(String url, File targetFileOrDir, int timeout, StreamProgress streamProgress) {
|
||||
return requestDownload(url, timeout).writeBodyForFile(targetFileOrDir, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param out 将下载内容写到输出流中 {@link OutputStream}
|
||||
* @param isCloseOut 是否关闭输出流
|
||||
* @param streamProgress 进度条
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long download(String url, OutputStream out, boolean isCloseOut, StreamProgress streamProgress) {
|
||||
Assert.notNull(out, "[out] is null !");
|
||||
|
||||
return requestDownload(url, -1).writeBody(out, isCloseOut, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求下载文件
|
||||
*
|
||||
* @param url 请求下载文件地址
|
||||
* @param timeout 超时时间
|
||||
* @return HttpResponse
|
||||
* @since 5.4.1
|
||||
*/
|
||||
private static aiyh.utils.tool.cn.hutool.http.HttpResponse requestDownload(String url, int timeout) {
|
||||
Assert.notBlank(url, "[url] is blank !");
|
||||
|
||||
final HttpResponse response = HttpUtil.createGet(url, true)
|
||||
.timeout(timeout)
|
||||
.executeAsync();
|
||||
|
||||
if (response.isOk()) {
|
||||
return response;
|
||||
}
|
||||
|
||||
throw new HttpException("Server response error with status code: [{}]", response.getStatus());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* HTTP异常
|
||||
*
|
||||
* @author xiaoleilu
|
||||
*/
|
||||
public class HttpException extends RuntimeException {
|
||||
private static final long serialVersionUID = 8247610319171014183L;
|
||||
|
||||
public HttpException(Throwable e) {
|
||||
super(e.getMessage(), e);
|
||||
}
|
||||
|
||||
public HttpException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public HttpException(String messageTemplate, Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params));
|
||||
}
|
||||
|
||||
public HttpException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
|
||||
public HttpException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, throwable, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
public HttpException(Throwable throwable, String messageTemplate, Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params), throwable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.RandomUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.cookie.GlobalCookieManager;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.CookieManager;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
/**
|
||||
* HTTP 全局参数配置
|
||||
*
|
||||
* @author Looly
|
||||
* @since 4.6.2
|
||||
*/
|
||||
public class HttpGlobalConfig implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* -1: 含义,永不超时。
|
||||
* 如果:设置timeout = 3s(3000 ms), 那一次请求最大超时:就是:6s
|
||||
* 官方含义:timeout of zero is interpreted as an infinite timeout. (0的超时被解释为无限超时。)
|
||||
* 这里实际项目一定要进行修改,防止把系统拖死.
|
||||
* 底层调用:{@link HttpURLConnection#setReadTimeout(int)} 同时设置: 读取超时
|
||||
* 底层调用:{@link HttpURLConnection#setConnectTimeout(int)} 同时设置: 连接超时
|
||||
*/
|
||||
private static int timeout = -1;
|
||||
private static boolean isAllowPatch = false;
|
||||
private static String boundary = "--------------------Hutool_" + RandomUtil.randomString(16);
|
||||
private static int maxRedirectCount = 0;
|
||||
private static boolean ignoreEOFError = true;
|
||||
private static boolean decodeUrl = false;
|
||||
|
||||
/**
|
||||
* 获取全局默认的超时时长
|
||||
*
|
||||
* @return 全局默认的超时时长
|
||||
*/
|
||||
public static int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认的连接和读取超时时长<br>
|
||||
* -1: 含义,永不超时。<br>
|
||||
* 如果:设置timeout = 3s(3000 ms), 那一次请求最大超时:就是:6s<br>
|
||||
* 官方含义:timeout of zero is interpreted as an infinite timeout. (0的超时被解释为无限超时。)<br>
|
||||
* 这里实际项目一定要进行修改,防止把系统拖死.<br>
|
||||
* 底层调用:{@link HttpURLConnection#setReadTimeout(int)} 同时设置: 读取超时<br>
|
||||
* 底层调用:{@link HttpURLConnection#setConnectTimeout(int)} 同时设置: 连接超时
|
||||
*
|
||||
* @param customTimeout 超时时长
|
||||
*/
|
||||
synchronized public static void setTimeout(int customTimeout) {
|
||||
timeout = customTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局默认的Multipart边界
|
||||
*
|
||||
* @return 全局默认的Multipart边界
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public static String getBoundary() {
|
||||
return boundary;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认的Multipart边界
|
||||
*
|
||||
* @param customBoundary 自定义Multipart边界
|
||||
* @since 5.7.17
|
||||
*/
|
||||
synchronized public static void setBoundary(String customBoundary) {
|
||||
boundary = customBoundary;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局默认的最大重定向次数,如设置0表示不重定向<br>
|
||||
* 如果设置为1,表示重定向一次,即请求两次
|
||||
*
|
||||
* @return 全局默认的最大重定向次数
|
||||
* @since 5.7.19
|
||||
*/
|
||||
public static int getMaxRedirectCount() {
|
||||
return maxRedirectCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认全局默认的最大重定向次数,如设置0表示不重定向<br>
|
||||
* 如果设置为1,表示重定向一次,即请求两次
|
||||
*
|
||||
* @param customMaxRedirectCount 全局默认的最大重定向次数
|
||||
* @since 5.7.19
|
||||
*/
|
||||
synchronized public static void setMaxRedirectCount(int customMaxRedirectCount) {
|
||||
maxRedirectCount = customMaxRedirectCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取是否忽略响应读取时可能的EOF异常。<br>
|
||||
* 在Http协议中,对于Transfer-Encoding: Chunked在正常情况下末尾会写入一个Length为0的的chunk标识完整结束。<br>
|
||||
* 如果服务端未遵循这个规范或响应没有正常结束,会报EOF异常,此选项用于是否忽略这个异常。
|
||||
*
|
||||
* @return 是否忽略响应读取时可能的EOF异常
|
||||
* @since 5.7.20
|
||||
*/
|
||||
public static boolean isIgnoreEOFError() {
|
||||
return ignoreEOFError;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否忽略响应读取时可能的EOF异常。<br>
|
||||
* 在Http协议中,对于Transfer-Encoding: Chunked在正常情况下末尾会写入一个Length为0的的chunk标识完整结束。<br>
|
||||
* 如果服务端未遵循这个规范或响应没有正常结束,会报EOF异常,此选项用于是否忽略这个异常。
|
||||
*
|
||||
* @param customIgnoreEOFError 是否忽略响应读取时可能的EOF异常。
|
||||
* @since 5.7.20
|
||||
*/
|
||||
synchronized public static void setIgnoreEOFError(boolean customIgnoreEOFError) {
|
||||
ignoreEOFError = customIgnoreEOFError;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取是否忽略解码URL,包括URL中的Path部分和Param部分。<br>
|
||||
* 在构建Http请求时,用户传入的URL可能有编码后和未编码的内容混合在一起,如果此参数为{@code true},则会统一解码编码后的参数,<br>
|
||||
* 按照RFC3986规范,在发送请求时,全部编码之。如果为{@code false},则不会解码已经编码的内容,在请求时只编码需要编码的部分。
|
||||
*
|
||||
* @return 是否忽略解码URL
|
||||
* @since 5.7.22
|
||||
*/
|
||||
public static boolean isDecodeUrl() {
|
||||
return decodeUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否忽略解码URL,包括URL中的Path部分和Param部分。<br>
|
||||
* 在构建Http请求时,用户传入的URL可能有编码后和未编码的内容混合在一起,如果此参数为{@code true},则会统一解码编码后的参数,<br>
|
||||
* 按照RFC3986规范,在发送请求时,全部编码之。如果为{@code false},则不会解码已经编码的内容,在请求时只编码需要编码的部分。
|
||||
*
|
||||
* @param customDecodeUrl 是否忽略解码URL
|
||||
* @since 5.7.22
|
||||
*/
|
||||
synchronized public static void setDecodeUrl(boolean customDecodeUrl) {
|
||||
decodeUrl = customDecodeUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Cookie管理器,用于自定义Cookie管理
|
||||
*
|
||||
* @return {@link CookieManager}
|
||||
* @see GlobalCookieManager#getCookieManager()
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public static CookieManager getCookieManager() {
|
||||
return GlobalCookieManager.getCookieManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义{@link CookieManager}
|
||||
*
|
||||
* @param customCookieManager 自定义的{@link CookieManager}
|
||||
* @see GlobalCookieManager#setCookieManager(CookieManager)
|
||||
* @since 4.5.14
|
||||
*/
|
||||
synchronized public static void setCookieManager(CookieManager customCookieManager) {
|
||||
GlobalCookieManager.setCookieManager(customCookieManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭Cookie
|
||||
*
|
||||
* @see GlobalCookieManager#setCookieManager(CookieManager)
|
||||
* @since 4.1.9
|
||||
*/
|
||||
synchronized public static void closeCookie() {
|
||||
GlobalCookieManager.setCookieManager(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加支持的METHOD方法<br>
|
||||
* 此方法通过注入方式修改{@link HttpURLConnection}中的methods静态属性,增加PATCH方法<br>
|
||||
* see: <a href="https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch">https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch</a>
|
||||
*
|
||||
* @since 5.7.4
|
||||
*/
|
||||
synchronized public static void allowPatch() {
|
||||
if (isAllowPatch) {
|
||||
return;
|
||||
}
|
||||
final Field methodsField = ReflectUtil.getField(HttpURLConnection.class, "methods");
|
||||
if (null == methodsField) {
|
||||
throw new HttpException("None static field [methods] with Java version: [{}]", System.getProperty("java.version"));
|
||||
}
|
||||
|
||||
// 去除final修饰
|
||||
ReflectUtil.removeFinalModify(methodsField);
|
||||
final String[] methods = {
|
||||
"GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
|
||||
};
|
||||
ReflectUtil.setFieldValue(null, methodsField, methods);
|
||||
|
||||
// 检查注入是否成功
|
||||
final Object staticFieldValue = ReflectUtil.getStaticFieldValue(methodsField);
|
||||
if (!ArrayUtil.equals(methods, staticFieldValue)) {
|
||||
throw new HttpException("Inject value to field [methods] failed!");
|
||||
}
|
||||
|
||||
isAllowPatch = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
/**
|
||||
* HTTP输入流,此流用于包装Http请求响应内容的流,用于解析各种压缩、分段的响应流内容
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class HttpInputStream extends InputStream {
|
||||
|
||||
/** 原始流 */
|
||||
private InputStream in;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param response 响应对象
|
||||
*/
|
||||
public HttpInputStream(aiyh.utils.tool.cn.hutool.http.HttpResponse response) {
|
||||
init(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return this.in.read();
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
return this.in.read(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
return this.in.skip(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return this.in.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.in.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mark(int readlimit) {
|
||||
this.in.mark(readlimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
this.in.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return this.in.markSupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化流
|
||||
*
|
||||
* @param response 响应对象
|
||||
*/
|
||||
private void init(HttpResponse response) {
|
||||
try {
|
||||
this.in = (response.status < HttpStatus.HTTP_BAD_REQUEST) ? response.httpConnection.getInputStream() : response.httpConnection.getErrorStream();
|
||||
} catch (IOException e) {
|
||||
if (false == (e instanceof FileNotFoundException)) {
|
||||
throw new HttpException(e);
|
||||
}
|
||||
// 服务器无返回内容,忽略之
|
||||
}
|
||||
|
||||
// 在一些情况下,返回的流为null,此时提供状态码说明
|
||||
if (null == this.in) {
|
||||
this.in = new ByteArrayInputStream(StrUtil.format("Error request, response status: {}", response.status).getBytes());
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.isGzip() && false == (response.in instanceof GZIPInputStream)) {
|
||||
// Accept-Encoding: gzip
|
||||
try {
|
||||
this.in = new GZIPInputStream(this.in);
|
||||
} catch (IOException e) {
|
||||
// 在类似于Head等方法中无body返回,此时GZIPInputStream构造会出现错误,在此忽略此错误读取普通数据
|
||||
// ignore
|
||||
}
|
||||
} else if (response.isDeflate() && false == (this.in instanceof InflaterInputStream)) {
|
||||
// Accept-Encoding: defalte
|
||||
this.in = new InflaterInputStream(this.in, new Inflater(true));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Http拦截器接口,通过实现此接口,完成请求发起前或结束后对请求的编辑工作
|
||||
*
|
||||
* @param <T> 过滤参数类型,HttpRequest或者HttpResponse
|
||||
* @author looly
|
||||
* @since 5.7.16
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface HttpInterceptor<T extends aiyh.utils.tool.cn.hutool.http.HttpBase<T>> {
|
||||
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param httpObj 请求或响应对象
|
||||
*/
|
||||
void process(T httpObj);
|
||||
|
||||
/**
|
||||
* 拦截器链
|
||||
*
|
||||
* @param <T> 过滤参数类型,HttpRequest或者HttpResponse
|
||||
* @author looly
|
||||
* @since 5.7.16
|
||||
*/
|
||||
class Chain<T extends HttpBase<T>> implements aiyh.utils.tool.cn.hutool.core.lang.Chain<HttpInterceptor<T>, Chain<T>> {
|
||||
private final List<HttpInterceptor<T>> interceptors = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public Chain<T> addChain(HttpInterceptor<T> element) {
|
||||
interceptors.add(element);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<HttpInterceptor<T>> iterator() {
|
||||
return interceptors.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空
|
||||
*
|
||||
* @return this
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public Chain<T> clear() {
|
||||
interceptors.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,56 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.resource.Resource;
|
||||
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* HTTP资源,可自定义Content-Type
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public class HttpResource implements Resource, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Resource resource;
|
||||
private final String contentType;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param resource 资源,非空
|
||||
* @param contentType Content-Type类型,{@code null}表示不设置
|
||||
*/
|
||||
public HttpResource(Resource resource, String contentType) {
|
||||
this.resource = Assert.notNull(resource, "Resource must be not null !");
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return resource.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() {
|
||||
return resource.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getStream() {
|
||||
return resource.getStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义Content-Type类型
|
||||
*
|
||||
* @return Content-Type类型
|
||||
*/
|
||||
public String getContentType() {
|
||||
return this.contentType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,644 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.FastByteArrayOutputStream;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.FileUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.StreamProgress;
|
||||
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ObjUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ReUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.URLUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.cookie.GlobalCookieManager;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpCookie;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Http响应类<br>
|
||||
* 非线程安全对象
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
|
||||
|
||||
/**
|
||||
* Http配置
|
||||
*/
|
||||
protected HttpConfig config;
|
||||
/**
|
||||
* 持有连接对象
|
||||
*/
|
||||
protected HttpConnection httpConnection;
|
||||
/**
|
||||
* Http请求原始流
|
||||
*/
|
||||
protected InputStream in;
|
||||
/**
|
||||
* 是否异步,异步下只持有流,否则将在初始化时直接读取body内容
|
||||
*/
|
||||
private volatile boolean isAsync;
|
||||
/**
|
||||
* 响应状态码
|
||||
*/
|
||||
protected int status;
|
||||
/**
|
||||
* 是否忽略读取Http响应体
|
||||
*/
|
||||
private final boolean ignoreBody;
|
||||
/**
|
||||
* 从响应中获取的编码
|
||||
*/
|
||||
private Charset charsetFromResponse;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param httpConnection {@link HttpConnection}
|
||||
* @param config Http配置
|
||||
* @param charset 编码,从请求编码中获取默认编码
|
||||
* @param isAsync 是否异步
|
||||
* @param isIgnoreBody 是否忽略读取响应体
|
||||
* @since 3.1.2
|
||||
*/
|
||||
protected HttpResponse(HttpConnection httpConnection, HttpConfig config, Charset charset, boolean isAsync, boolean isIgnoreBody) {
|
||||
this.httpConnection = httpConnection;
|
||||
this.config = config;
|
||||
this.charset = charset;
|
||||
this.isAsync = isAsync;
|
||||
this.ignoreBody = isIgnoreBody;
|
||||
initWithDisconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态码
|
||||
*
|
||||
* @return 状态码
|
||||
*/
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求是否成功,判断依据为:状态码范围在200~299内。
|
||||
*
|
||||
* @return 是否成功请求
|
||||
* @since 4.1.9
|
||||
*/
|
||||
public boolean isOk() {
|
||||
return this.status >= 200 && this.status < 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步<br>
|
||||
* 如果为异步状态,则暂时不读取服务器中响应的内容,而是持有Http链接的{@link InputStream}。<br>
|
||||
* 当调用此方法时,异步状态转为同步状态,此时从Http链接流中读取body内容并暂存在内容中。如果已经是同步状态,则不进行任何操作。
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public HttpResponse sync() {
|
||||
return this.isAsync ? forceSync() : this;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Http Response Header start
|
||||
|
||||
/**
|
||||
* 获取内容编码
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String contentEncoding() {
|
||||
return header(aiyh.utils.tool.cn.hutool.http.Header.CONTENT_ENCODING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容长度,以下情况长度无效:
|
||||
* <ul>
|
||||
* <li>Transfer-Encoding: Chunked</li>
|
||||
* <li>Content-Encoding: XXX</li>
|
||||
* </ul>
|
||||
* 参考:https://blog.csdn.net/jiang7701037/article/details/86304302
|
||||
*
|
||||
* @return 长度,-1表示服务端未返回或长度无效
|
||||
* @since 5.7.9
|
||||
*/
|
||||
public long contentLength() {
|
||||
long contentLength = Convert.toLong(header(aiyh.utils.tool.cn.hutool.http.Header.CONTENT_LENGTH), -1L);
|
||||
if (contentLength > 0 && (isChunked() || StrUtil.isNotBlank(contentEncoding()))) {
|
||||
//按照HTTP协议规范,在 Transfer-Encoding和Content-Encoding设置后 Content-Length 无效。
|
||||
contentLength = -1;
|
||||
}
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为gzip压缩过的内容
|
||||
*
|
||||
* @return 是否为gzip压缩过的内容
|
||||
*/
|
||||
public boolean isGzip() {
|
||||
final String contentEncoding = contentEncoding();
|
||||
return "gzip".equalsIgnoreCase(contentEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为zlib(Deflate)压缩过的内容
|
||||
*
|
||||
* @return 是否为zlib(Deflate)压缩过的内容
|
||||
* @since 4.5.7
|
||||
*/
|
||||
public boolean isDeflate() {
|
||||
final String contentEncoding = contentEncoding();
|
||||
return "deflate".equalsIgnoreCase(contentEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为Transfer-Encoding:Chunked的内容
|
||||
*
|
||||
* @return 是否为Transfer-Encoding:Chunked的内容
|
||||
* @since 4.6.2
|
||||
*/
|
||||
public boolean isChunked() {
|
||||
final String transferEncoding = header(aiyh.utils.tool.cn.hutool.http.Header.TRANSFER_ENCODING);
|
||||
return "Chunked".equalsIgnoreCase(transferEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本次请求服务器返回的Cookie信息
|
||||
*
|
||||
* @return Cookie字符串
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public String getCookieStr() {
|
||||
return header(aiyh.utils.tool.cn.hutool.http.Header.SET_COOKIE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Cookie
|
||||
*
|
||||
* @return Cookie列表
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public List<HttpCookie> getCookies() {
|
||||
return GlobalCookieManager.getCookies(this.httpConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Cookie
|
||||
*
|
||||
* @param name Cookie名
|
||||
* @return {@link HttpCookie}
|
||||
* @since 4.1.4
|
||||
*/
|
||||
public HttpCookie getCookie(String name) {
|
||||
List<HttpCookie> cookie = getCookies();
|
||||
if (null != cookie) {
|
||||
for (HttpCookie httpCookie : cookie) {
|
||||
if (httpCookie.getName().equals(name)) {
|
||||
return httpCookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Cookie值
|
||||
*
|
||||
* @param name Cookie名
|
||||
* @return Cookie值
|
||||
* @since 4.1.4
|
||||
*/
|
||||
public String getCookieValue(String name) {
|
||||
HttpCookie cookie = getCookie(name);
|
||||
return (null == cookie) ? null : cookie.getValue();
|
||||
}
|
||||
// ---------------------------------------------------------------- Http Response Header end
|
||||
|
||||
// ---------------------------------------------------------------- Body start
|
||||
|
||||
/**
|
||||
* 获得服务区响应流<br>
|
||||
* 异步模式下获取Http原生流,同步模式下获取获取到的在内存中的副本<br>
|
||||
* 如果想在同步模式下获取流,请先调用{@link #sync()}方法强制同步<br>
|
||||
* 流获取后处理完毕需关闭此类
|
||||
*
|
||||
* @return 响应流
|
||||
*/
|
||||
public InputStream bodyStream() {
|
||||
if (isAsync) {
|
||||
return this.in;
|
||||
}
|
||||
return new ByteArrayInputStream(this.bodyBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应流字节码<br>
|
||||
* 此方法会转为同步模式
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
@Override
|
||||
public byte[] bodyBytes() {
|
||||
sync();
|
||||
return this.bodyBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置主体字节码<br>
|
||||
* 需在此方法调用前使用charset方法设置编码,否则使用默认编码UTF-8
|
||||
*
|
||||
* @param bodyBytes 主体
|
||||
* @return this
|
||||
*/
|
||||
public HttpResponse body(byte[] bodyBytes) {
|
||||
sync();
|
||||
if (null != bodyBytes) {
|
||||
this.bodyBytes = bodyBytes;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应主体
|
||||
*
|
||||
* @return String
|
||||
* @throws HttpException 包装IO异常
|
||||
*/
|
||||
public String body() throws HttpException {
|
||||
return HttpUtil.getString(bodyBytes(), this.charset, null == this.charsetFromResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将响应内容写出到{@link OutputStream}<br>
|
||||
* 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出<br>
|
||||
* 写出后会关闭Http流(异步模式)
|
||||
*
|
||||
* @param out 写出的流
|
||||
* @param isCloseOut 是否关闭输出流
|
||||
* @param streamProgress 进度显示接口,通过实现此接口显示下载进度
|
||||
* @return 写出bytes数
|
||||
* @since 3.3.2
|
||||
*/
|
||||
public long writeBody(OutputStream out, boolean isCloseOut, StreamProgress streamProgress) {
|
||||
Assert.notNull(out, "[out] must be not null!");
|
||||
final long contentLength = contentLength();
|
||||
try {
|
||||
return copyBody(bodyStream(), out, contentLength, streamProgress, this.config.ignoreEOFError);
|
||||
} finally {
|
||||
IoUtil.close(this);
|
||||
if (isCloseOut) {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将响应内容写出到文件<br>
|
||||
* 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出<br>
|
||||
* 写出后会关闭Http流(异步模式)
|
||||
*
|
||||
* @param targetFileOrDir 写出到的文件或目录
|
||||
* @param streamProgress 进度显示接口,通过实现此接口显示下载进度
|
||||
* @return 写出bytes数
|
||||
* @since 3.3.2
|
||||
*/
|
||||
public long writeBody(File targetFileOrDir, StreamProgress streamProgress) {
|
||||
Assert.notNull(targetFileOrDir, "[targetFileOrDir] must be not null!");
|
||||
|
||||
final File outFile = completeFileNameFromHeader(targetFileOrDir);
|
||||
return writeBody(FileUtil.getOutputStream(outFile), true, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将响应内容写出到文件-避免未完成的文件<br>
|
||||
* 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出<br>
|
||||
* 写出后会关闭Http流(异步模式)<br>
|
||||
* 来自:https://gitee.com/dromara/hutool/pulls/407<br>
|
||||
* 此方法原理是先在目标文件同级目录下创建临时文件,下载之,等下载完毕后重命名,避免因下载错误导致的文件不完整。
|
||||
*
|
||||
* @param targetFileOrDir 写出到的文件或目录
|
||||
* @param tempFileSuffix 临时文件后缀,默认".temp"
|
||||
* @param streamProgress 进度显示接口,通过实现此接口显示下载进度
|
||||
* @return 写出bytes数
|
||||
* @since 5.7.12
|
||||
*/
|
||||
public long writeBody(File targetFileOrDir, String tempFileSuffix, StreamProgress streamProgress) {
|
||||
Assert.notNull(targetFileOrDir, "[targetFileOrDir] must be not null!");
|
||||
|
||||
File outFile = completeFileNameFromHeader(targetFileOrDir);
|
||||
|
||||
if (StrUtil.isBlank(tempFileSuffix)) {
|
||||
tempFileSuffix = ".temp";
|
||||
} else {
|
||||
tempFileSuffix = StrUtil.addPrefixIfNot(tempFileSuffix, StrUtil.DOT);
|
||||
}
|
||||
|
||||
// 目标文件真实名称
|
||||
final String fileName = outFile.getName();
|
||||
// 临时文件名称
|
||||
final String tempFileName = fileName + tempFileSuffix;
|
||||
|
||||
// 临时文件
|
||||
outFile = new File(outFile.getParentFile(), tempFileName);
|
||||
|
||||
long length;
|
||||
try {
|
||||
length = writeBody(outFile, streamProgress);
|
||||
// 重命名下载好的临时文件
|
||||
FileUtil.rename(outFile, fileName, true);
|
||||
} catch (Throwable e) {
|
||||
// 异常则删除临时文件
|
||||
FileUtil.del(outFile);
|
||||
throw new HttpException(e);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将响应内容写出到文件<br>
|
||||
* 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出<br>
|
||||
* 写出后会关闭Http流(异步模式)
|
||||
*
|
||||
* @param targetFileOrDir 写出到的文件
|
||||
* @param streamProgress 进度显示接口,通过实现此接口显示下载进度
|
||||
* @return 写出的文件
|
||||
* @since 5.6.4
|
||||
*/
|
||||
public File writeBodyForFile(File targetFileOrDir, StreamProgress streamProgress) {
|
||||
Assert.notNull(targetFileOrDir, "[targetFileOrDir] must be not null!");
|
||||
|
||||
final File outFile = completeFileNameFromHeader(targetFileOrDir);
|
||||
writeBody(FileUtil.getOutputStream(outFile), true, streamProgress);
|
||||
|
||||
return outFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将响应内容写出到文件<br>
|
||||
* 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出<br>
|
||||
* 写出后会关闭Http流(异步模式)
|
||||
*
|
||||
* @param targetFileOrDir 写出到的文件或目录
|
||||
* @return 写出bytes数
|
||||
* @since 3.3.2
|
||||
*/
|
||||
public long writeBody(File targetFileOrDir) {
|
||||
return writeBody(targetFileOrDir, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将响应内容写出到文件<br>
|
||||
* 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出<br>
|
||||
* 写出后会关闭Http流(异步模式)
|
||||
*
|
||||
* @param targetFileOrDir 写出到的文件或目录的路径
|
||||
* @return 写出bytes数
|
||||
* @since 3.3.2
|
||||
*/
|
||||
public long writeBody(String targetFileOrDir) {
|
||||
return writeBody(FileUtil.file(targetFileOrDir));
|
||||
}
|
||||
// ---------------------------------------------------------------- Body end
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
IoUtil.close(this.in);
|
||||
this.in = null;
|
||||
// 关闭连接
|
||||
this.httpConnection.disconnectQuietly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = StrUtil.builder();
|
||||
sb.append("Response Headers: ").append(StrUtil.CRLF);
|
||||
for (Entry<String, List<String>> entry : this.headers.entrySet()) {
|
||||
sb.append(" ").append(entry).append(StrUtil.CRLF);
|
||||
}
|
||||
|
||||
sb.append("Response Body: ").append(StrUtil.CRLF);
|
||||
sb.append(" ").append(this.body()).append(StrUtil.CRLF);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从响应头补全下载文件名
|
||||
*
|
||||
* @param targetFileOrDir 目标文件夹或者目标文件
|
||||
* @return File 保存的文件
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public File completeFileNameFromHeader(File targetFileOrDir) {
|
||||
if (false == targetFileOrDir.isDirectory()) {
|
||||
// 非目录直接返回
|
||||
return targetFileOrDir;
|
||||
}
|
||||
|
||||
// 从头信息中获取文件名
|
||||
String fileName = getFileNameFromDisposition(null);
|
||||
if (StrUtil.isBlank(fileName)) {
|
||||
final String path = httpConnection.getUrl().getPath();
|
||||
// 从路径中获取文件名
|
||||
fileName = StrUtil.subSuf(path, path.lastIndexOf('/') + 1);
|
||||
if (StrUtil.isBlank(fileName)) {
|
||||
// 编码后的路径做为文件名
|
||||
fileName = URLUtil.encodeQuery(path, charset);
|
||||
} else {
|
||||
// issue#I4K0FS@Gitee
|
||||
fileName = URLUtil.decode(fileName, charset);
|
||||
}
|
||||
}
|
||||
return FileUtil.file(targetFileOrDir, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Content-Disposition头中获取文件名
|
||||
* @param paramName 文件参数名
|
||||
*
|
||||
* @return 文件名,empty表示无
|
||||
*/
|
||||
public String getFileNameFromDisposition(String paramName) {
|
||||
paramName = ObjUtil.defaultIfNull(paramName, "filename");
|
||||
String fileName = null;
|
||||
final String disposition = header(Header.CONTENT_DISPOSITION);
|
||||
if (StrUtil.isNotBlank(disposition)) {
|
||||
fileName = ReUtil.get(paramName+"=\"(.*?)\"", disposition, 1);
|
||||
if (StrUtil.isBlank(fileName)) {
|
||||
fileName = StrUtil.subAfter(disposition, paramName + "=", true);
|
||||
}
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 初始化Http响应,并在报错时关闭连接。<br>
|
||||
* 初始化包括:
|
||||
*
|
||||
* <pre>
|
||||
* 1、读取Http状态
|
||||
* 2、读取头信息
|
||||
* 3、持有Http流,并不关闭流
|
||||
* </pre>
|
||||
*
|
||||
* @return this
|
||||
* @throws HttpException IO异常
|
||||
*/
|
||||
private HttpResponse initWithDisconnect() throws HttpException {
|
||||
try {
|
||||
init();
|
||||
} catch (HttpException e) {
|
||||
this.httpConnection.disconnectQuietly();
|
||||
throw e;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Http响应<br>
|
||||
* 初始化包括:
|
||||
*
|
||||
* <pre>
|
||||
* 1、读取Http状态
|
||||
* 2、读取头信息
|
||||
* 3、持有Http流,并不关闭流
|
||||
* </pre>
|
||||
*
|
||||
* @return this
|
||||
* @throws HttpException IO异常
|
||||
*/
|
||||
private HttpResponse init() throws HttpException {
|
||||
// 获取响应状态码
|
||||
try {
|
||||
this.status = httpConnection.responseCode();
|
||||
} catch (IOException e) {
|
||||
if (false == (e instanceof FileNotFoundException)) {
|
||||
throw new HttpException(e);
|
||||
}
|
||||
// 服务器无返回内容,忽略之
|
||||
}
|
||||
|
||||
|
||||
// 读取响应头信息
|
||||
try {
|
||||
this.headers = httpConnection.headers();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// ignore
|
||||
// StaticLog.warn(e, e.getMessage());
|
||||
}
|
||||
|
||||
// 存储服务端设置的Cookie信息
|
||||
GlobalCookieManager.store(httpConnection);
|
||||
|
||||
// 获取响应编码
|
||||
final Charset charset = httpConnection.getCharset();
|
||||
this.charsetFromResponse = charset;
|
||||
if (null != charset) {
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
// 获取响应内容流
|
||||
this.in = new HttpInputStream(this);
|
||||
|
||||
// 同步情况下强制同步
|
||||
return this.isAsync ? this : forceSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制同步,用于初始化<br>
|
||||
* 强制同步后变化如下:
|
||||
*
|
||||
* <pre>
|
||||
* 1、读取body内容到内存
|
||||
* 2、异步状态设为false(变为同步状态)
|
||||
* 3、关闭Http流
|
||||
* 4、断开与服务器连接
|
||||
* </pre>
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
private HttpResponse forceSync() {
|
||||
// 非同步状态转为同步状态
|
||||
try {
|
||||
this.readBody(this.in);
|
||||
} catch (IORuntimeException e) {
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (e.getCause() instanceof FileNotFoundException) {
|
||||
// 服务器无返回内容,忽略之
|
||||
} else {
|
||||
throw new HttpException(e);
|
||||
}
|
||||
} finally {
|
||||
if (this.isAsync) {
|
||||
this.isAsync = false;
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取主体,忽略EOFException异常
|
||||
*
|
||||
* @param in 输入流
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
private void readBody(InputStream in) throws IORuntimeException {
|
||||
if (ignoreBody) {
|
||||
return;
|
||||
}
|
||||
|
||||
final long contentLength = contentLength();
|
||||
final FastByteArrayOutputStream out = new FastByteArrayOutputStream((int) contentLength);
|
||||
copyBody(in, out, contentLength, null, this.config.ignoreEOFError);
|
||||
this.bodyBytes = out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将响应内容写出到{@link OutputStream}<br>
|
||||
* 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出<br>
|
||||
* 写出后会关闭Http流(异步模式)
|
||||
*
|
||||
* @param in 输入流
|
||||
* @param out 写出的流
|
||||
* @param contentLength 总长度,-1表示未知
|
||||
* @param streamProgress 进度显示接口,通过实现此接口显示下载进度
|
||||
* @param isIgnoreEOFError 是否忽略响应读取时可能的EOF异常
|
||||
* @return 拷贝长度
|
||||
*/
|
||||
private static long copyBody(InputStream in, OutputStream out, long contentLength, StreamProgress streamProgress, boolean isIgnoreEOFError) {
|
||||
if (null == out) {
|
||||
throw new NullPointerException("[out] is null!");
|
||||
}
|
||||
|
||||
long copyLength = -1;
|
||||
try {
|
||||
copyLength = IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE, contentLength, streamProgress);
|
||||
} catch (IORuntimeException e) {
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (isIgnoreEOFError
|
||||
&& (e.getCause() instanceof EOFException || StrUtil.containsIgnoreCase(e.getMessage(), "Premature EOF"))) {
|
||||
// 忽略读取HTTP流中的EOF错误
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return copyLength;
|
||||
}
|
||||
// ---------------------------------------------------------------- Private method end
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
/**
|
||||
* HTTP状态码
|
||||
*
|
||||
* @author Looly
|
||||
* @see java.net.HttpURLConnection
|
||||
*
|
||||
*/
|
||||
public class HttpStatus {
|
||||
|
||||
/* 2XX: generally "OK" */
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 200: OK.
|
||||
*/
|
||||
public static final int HTTP_OK = 200;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 201: Created.
|
||||
*/
|
||||
public static final int HTTP_CREATED = 201;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 202: Accepted.
|
||||
*/
|
||||
public static final int HTTP_ACCEPTED = 202;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 203: Non-Authoritative Information.
|
||||
*/
|
||||
public static final int HTTP_NOT_AUTHORITATIVE = 203;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 204: No Content.
|
||||
*/
|
||||
public static final int HTTP_NO_CONTENT = 204;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 205: Reset Content.
|
||||
*/
|
||||
public static final int HTTP_RESET = 205;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 206: Partial Content.
|
||||
*/
|
||||
public static final int HTTP_PARTIAL = 206;
|
||||
|
||||
/* 3XX: relocation/redirect */
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 300: Multiple Choices.
|
||||
*/
|
||||
public static final int HTTP_MULT_CHOICE = 300;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 301: Moved Permanently.
|
||||
*/
|
||||
public static final int HTTP_MOVED_PERM = 301;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 302: Temporary Redirect.
|
||||
*/
|
||||
public static final int HTTP_MOVED_TEMP = 302;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 303: See Other.
|
||||
*/
|
||||
public static final int HTTP_SEE_OTHER = 303;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 304: Not Modified.
|
||||
*/
|
||||
public static final int HTTP_NOT_MODIFIED = 304;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 305: Use Proxy.
|
||||
*/
|
||||
public static final int HTTP_USE_PROXY = 305;
|
||||
|
||||
/**
|
||||
* HTTP 1.1 Status-Code 307: Temporary Redirect.<br>
|
||||
* 见:RFC-7231
|
||||
*/
|
||||
public static final int HTTP_TEMP_REDIRECT = 307;
|
||||
|
||||
/**
|
||||
* HTTP 1.1 Status-Code 308: Permanent Redirect 永久重定向<br>
|
||||
* 见:RFC-7231
|
||||
*/
|
||||
public static final int HTTP_PERMANENT_REDIRECT = 308;
|
||||
|
||||
/* 4XX: client error */
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 400: Bad Request.
|
||||
*/
|
||||
public static final int HTTP_BAD_REQUEST = 400;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 401: Unauthorized.
|
||||
*/
|
||||
public static final int HTTP_UNAUTHORIZED = 401;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 402: Payment Required.
|
||||
*/
|
||||
public static final int HTTP_PAYMENT_REQUIRED = 402;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 403: Forbidden.
|
||||
*/
|
||||
public static final int HTTP_FORBIDDEN = 403;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 404: Not Found.
|
||||
*/
|
||||
public static final int HTTP_NOT_FOUND = 404;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 405: Method Not Allowed.
|
||||
*/
|
||||
public static final int HTTP_BAD_METHOD = 405;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 406: Not Acceptable.
|
||||
*/
|
||||
public static final int HTTP_NOT_ACCEPTABLE = 406;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 407: Proxy Authentication Required.
|
||||
*/
|
||||
public static final int HTTP_PROXY_AUTH = 407;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 408: Request Time-Out.
|
||||
*/
|
||||
public static final int HTTP_CLIENT_TIMEOUT = 408;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 409: Conflict.
|
||||
*/
|
||||
public static final int HTTP_CONFLICT = 409;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 410: Gone.
|
||||
*/
|
||||
public static final int HTTP_GONE = 410;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 411: Length Required.
|
||||
*/
|
||||
public static final int HTTP_LENGTH_REQUIRED = 411;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 412: Precondition Failed.
|
||||
*/
|
||||
public static final int HTTP_PRECON_FAILED = 412;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 413: Request Entity Too Large.
|
||||
*/
|
||||
public static final int HTTP_ENTITY_TOO_LARGE = 413;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 414: Request-URI Too Large.
|
||||
*/
|
||||
public static final int HTTP_REQ_TOO_LONG = 414;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 415: Unsupported Media Type.
|
||||
*/
|
||||
public static final int HTTP_UNSUPPORTED_TYPE = 415;
|
||||
|
||||
/* 5XX: server error */
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 500: Internal Server Error.
|
||||
*/
|
||||
public static final int HTTP_INTERNAL_ERROR = 500;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 501: Not Implemented.
|
||||
*/
|
||||
public static final int HTTP_NOT_IMPLEMENTED = 501;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 502: Bad Gateway.
|
||||
*/
|
||||
public static final int HTTP_BAD_GATEWAY = 502;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 503: Service Unavailable.
|
||||
*/
|
||||
public static final int HTTP_UNAVAILABLE = 503;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 504: Gateway Timeout.
|
||||
*/
|
||||
public static final int HTTP_GATEWAY_TIMEOUT = 504;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 505: HTTP Version Not Supported.
|
||||
*/
|
||||
public static final int HTTP_VERSION = 505;
|
||||
|
||||
/**
|
||||
* 是否为重定向状态码
|
||||
* @param responseCode 被检查的状态码
|
||||
* @return 是否为重定向状态码
|
||||
* @since 5.6.3
|
||||
*/
|
||||
public static boolean isRedirected(int responseCode){
|
||||
return responseCode == HTTP_MOVED_PERM
|
||||
|| responseCode == HTTP_MOVED_TEMP
|
||||
|| responseCode == HTTP_SEE_OTHER
|
||||
// issue#1504@Github,307和308是RFC 7538中http 1.1定义的规范
|
||||
|| responseCode == HTTP_TEMP_REDIRECT
|
||||
|| responseCode == HTTP_PERMANENT_REDIRECT;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,893 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.codec.Base64;
|
||||
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.FileUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.StreamProgress;
|
||||
import aiyh.utils.tool.cn.hutool.core.map.MapUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.net.RFC3986;
|
||||
import aiyh.utils.tool.cn.hutool.core.net.url.UrlQuery;
|
||||
import aiyh.utils.tool.cn.hutool.core.text.StrBuilder;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.CharsetUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ReUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.URLUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.cookie.GlobalCookieManager;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.SimpleServer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.CookieManager;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Http请求工具类
|
||||
*
|
||||
* @author xiaoleilu
|
||||
*/
|
||||
public class HttpUtil {
|
||||
|
||||
/**
|
||||
* 正则:Content-Type中的编码信息
|
||||
*/
|
||||
public static final Pattern CHARSET_PATTERN = Pattern.compile("charset\\s*=\\s*([a-z0-9-]*)", Pattern.CASE_INSENSITIVE);
|
||||
/**
|
||||
* 正则:匹配meta标签的编码信息
|
||||
*/
|
||||
public static final Pattern META_CHARSET_PATTERN = Pattern.compile("<meta[^>]*?charset\\s*=\\s*['\"]?([a-z0-9-]*)", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
/**
|
||||
* 检测是否https
|
||||
*
|
||||
* @param url URL
|
||||
* @return 是否https
|
||||
*/
|
||||
public static boolean isHttps(String url) {
|
||||
return StrUtil.startWithIgnoreCase(url, "https:");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否http
|
||||
*
|
||||
* @param url URL
|
||||
* @return 是否http
|
||||
* @since 5.3.8
|
||||
*/
|
||||
public static boolean isHttp(String url) {
|
||||
return StrUtil.startWithIgnoreCase(url, "http:");
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Http请求对象
|
||||
*
|
||||
* @param method 方法枚举{@link aiyh.utils.tool.cn.hutool.http.Method}
|
||||
* @param url 请求的URL,可以使HTTP或者HTTPS
|
||||
* @return {@link aiyh.utils.tool.cn.hutool.http.HttpRequest}
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static aiyh.utils.tool.cn.hutool.http.HttpRequest createRequest(Method method, String url) {
|
||||
return aiyh.utils.tool.cn.hutool.http.HttpRequest.of(url).method(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Http GET请求对象
|
||||
*
|
||||
* @param url 请求的URL,可以使HTTP或者HTTPS
|
||||
* @return {@link aiyh.utils.tool.cn.hutool.http.HttpRequest}
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static aiyh.utils.tool.cn.hutool.http.HttpRequest createGet(String url) {
|
||||
return createGet(url, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Http GET请求对象
|
||||
*
|
||||
* @param url 请求的URL,可以使HTTP或者HTTPS
|
||||
* @param isFollowRedirects 是否打开重定向
|
||||
* @return {@link aiyh.utils.tool.cn.hutool.http.HttpRequest}
|
||||
* @since 5.6.4
|
||||
*/
|
||||
public static aiyh.utils.tool.cn.hutool.http.HttpRequest createGet(String url, boolean isFollowRedirects) {
|
||||
return aiyh.utils.tool.cn.hutool.http.HttpRequest.get(url).setFollowRedirects(isFollowRedirects);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Http POST请求对象
|
||||
*
|
||||
* @param url 请求的URL,可以使HTTP或者HTTPS
|
||||
* @return {@link aiyh.utils.tool.cn.hutool.http.HttpRequest}
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static aiyh.utils.tool.cn.hutool.http.HttpRequest createPost(String url) {
|
||||
return aiyh.utils.tool.cn.hutool.http.HttpRequest.post(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送get请求
|
||||
*
|
||||
* @param urlString 网址
|
||||
* @param customCharset 自定义请求字符集,如果字符集获取不到,使用此字符集
|
||||
* @return 返回内容,如果只检查状态码,正常只返回 "",不正常返回 null
|
||||
*/
|
||||
public static String get(String urlString, Charset customCharset) {
|
||||
return aiyh.utils.tool.cn.hutool.http.HttpRequest.get(urlString).charset(customCharset).execute().body();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送get请求
|
||||
*
|
||||
* @param urlString 网址
|
||||
* @return 返回内容,如果只检查状态码,正常只返回 "",不正常返回 null
|
||||
*/
|
||||
public static String get(String urlString) {
|
||||
return get(urlString, HttpGlobalConfig.getTimeout());
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送get请求
|
||||
*
|
||||
* @param urlString 网址
|
||||
* @param timeout 超时时长,-1表示默认超时,单位毫秒
|
||||
* @return 返回内容,如果只检查状态码,正常只返回 "",不正常返回 null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static String get(String urlString, int timeout) {
|
||||
return aiyh.utils.tool.cn.hutool.http.HttpRequest.get(urlString).timeout(timeout).execute().body();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送get请求
|
||||
*
|
||||
* @param urlString 网址
|
||||
* @param paramMap post表单数据
|
||||
* @return 返回数据
|
||||
*/
|
||||
public static String get(String urlString, Map<String, Object> paramMap) {
|
||||
return aiyh.utils.tool.cn.hutool.http.HttpRequest.get(urlString).form(paramMap).execute().body();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送get请求
|
||||
*
|
||||
* @param urlString 网址
|
||||
* @param paramMap post表单数据
|
||||
* @param timeout 超时时长,-1表示默认超时,单位毫秒
|
||||
* @return 返回数据
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public static String get(String urlString, Map<String, Object> paramMap, int timeout) {
|
||||
return aiyh.utils.tool.cn.hutool.http.HttpRequest.get(urlString).form(paramMap).timeout(timeout).execute().body();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送post请求
|
||||
*
|
||||
* @param urlString 网址
|
||||
* @param paramMap post表单数据
|
||||
* @return 返回数据
|
||||
*/
|
||||
public static String post(String urlString, Map<String, Object> paramMap) {
|
||||
return post(urlString, paramMap, HttpGlobalConfig.getTimeout());
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送post请求
|
||||
*
|
||||
* @param urlString 网址
|
||||
* @param paramMap post表单数据
|
||||
* @param timeout 超时时长,-1表示默认超时,单位毫秒
|
||||
* @return 返回数据
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static String post(String urlString, Map<String, Object> paramMap, int timeout) {
|
||||
return aiyh.utils.tool.cn.hutool.http.HttpRequest.post(urlString).form(paramMap).timeout(timeout).execute().body();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送post请求<br>
|
||||
* 请求体body参数支持两种类型:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 标准参数,例如 a=1&b=2 这种格式
|
||||
* 2. Rest模式,此时body需要传入一个JSON或者XML字符串,Hutool会自动绑定其对应的Content-Type
|
||||
* </pre>
|
||||
*
|
||||
* @param urlString 网址
|
||||
* @param body post表单数据
|
||||
* @return 返回数据
|
||||
*/
|
||||
public static String post(String urlString, String body) {
|
||||
return post(urlString, body, HttpGlobalConfig.getTimeout());
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送post请求<br>
|
||||
* 请求体body参数支持两种类型:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 标准参数,例如 a=1&b=2 这种格式
|
||||
* 2. Rest模式,此时body需要传入一个JSON或者XML字符串,Hutool会自动绑定其对应的Content-Type
|
||||
* </pre>
|
||||
*
|
||||
* @param urlString 网址
|
||||
* @param body post表单数据
|
||||
* @param timeout 超时时长,-1表示默认超时,单位毫秒
|
||||
* @return 返回数据
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static String post(String urlString, String body, int timeout) {
|
||||
return HttpRequest.post(urlString).timeout(timeout).body(body).execute().body();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------- download
|
||||
|
||||
/**
|
||||
* 下载远程文本
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param customCharsetName 自定义的字符集
|
||||
* @return 文本
|
||||
*/
|
||||
public static String downloadString(String url, String customCharsetName) {
|
||||
return downloadString(url, CharsetUtil.charset(customCharsetName), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文本
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param customCharset 自定义的字符集,可以使用{@link CharsetUtil#charset} 方法转换
|
||||
* @return 文本
|
||||
*/
|
||||
public static String downloadString(String url, Charset customCharset) {
|
||||
return downloadString(url, customCharset, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文本
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param customCharset 自定义的字符集,可以使用{@link CharsetUtil#charset} 方法转换
|
||||
* @param streamPress 进度条 {@link StreamProgress}
|
||||
* @return 文本
|
||||
*/
|
||||
public static String downloadString(String url, Charset customCharset, StreamProgress streamPress) {
|
||||
return HttpDownloader.downloadString(url, customCharset, streamPress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param dest 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long downloadFile(String url, String dest) {
|
||||
return downloadFile(url, FileUtil.file(dest));
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long downloadFile(String url, File destFile) {
|
||||
return downloadFile(url, destFile, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @return 文件大小
|
||||
* @since 4.0.4
|
||||
*/
|
||||
public static long downloadFile(String url, File destFile, int timeout) {
|
||||
return downloadFile(url, destFile, timeout, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param streamProgress 进度条
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long downloadFile(String url, File destFile, StreamProgress streamProgress) {
|
||||
return downloadFile(url, destFile, -1, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @param streamProgress 进度条
|
||||
* @return 文件大小
|
||||
* @since 4.0.4
|
||||
*/
|
||||
public static long downloadFile(String url, File destFile, int timeout, StreamProgress streamProgress) {
|
||||
return HttpDownloader.downloadFile(url, destFile, timeout, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param dest 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, String dest) {
|
||||
return downloadFileFromUrl(url, FileUtil.file(dest));
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, File destFile) {
|
||||
return downloadFileFromUrl(url, destFile, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, File destFile, int timeout) {
|
||||
return downloadFileFromUrl(url, destFile, timeout, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param streamProgress 进度条
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, File destFile, StreamProgress streamProgress) {
|
||||
return downloadFileFromUrl(url, destFile, -1, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @param streamProgress 进度条
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, File destFile, int timeout, StreamProgress streamProgress) {
|
||||
return HttpDownloader.downloadForFile(url, destFile, timeout, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param out 将下载内容写到输出流中 {@link OutputStream}
|
||||
* @param isCloseOut 是否关闭输出流
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long download(String url, OutputStream out, boolean isCloseOut) {
|
||||
return download(url, out, isCloseOut, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param out 将下载内容写到输出流中 {@link OutputStream}
|
||||
* @param isCloseOut 是否关闭输出流
|
||||
* @param streamProgress 进度条
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long download(String url, OutputStream out, boolean isCloseOut, StreamProgress streamProgress) {
|
||||
return HttpDownloader.download(url, out, isCloseOut, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件数据,支持30x跳转
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @return 文件数据
|
||||
* @since 5.3.6
|
||||
*/
|
||||
public static byte[] downloadBytes(String url) {
|
||||
return HttpDownloader.downloadBytes(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Map形式的Form表单数据转换为Url参数形式,会自动url编码键和值
|
||||
*
|
||||
* @param paramMap 表单数据
|
||||
* @return url参数
|
||||
*/
|
||||
public static String toParams(Map<String, ?> paramMap) {
|
||||
return toParams(paramMap, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Map形式的Form表单数据转换为Url参数形式<br>
|
||||
* 编码键和值对
|
||||
*
|
||||
* @param paramMap 表单数据
|
||||
* @param charsetName 编码
|
||||
* @return url参数
|
||||
* @deprecated 请使用 {@link #toParams(Map, Charset)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static String toParams(Map<String, Object> paramMap, String charsetName) {
|
||||
return toParams(paramMap, CharsetUtil.charset(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Map形式的Form表单数据转换为Url参数形式<br>
|
||||
* paramMap中如果key为空(null和"")会被忽略,如果value为null,会被做为空白符("")<br>
|
||||
* 会自动url编码键和值<br>
|
||||
* 此方法用于拼接URL中的Query部分,并不适用于POST请求中的表单
|
||||
*
|
||||
* <pre>
|
||||
* key1=v1&key2=&key3=v3
|
||||
* </pre>
|
||||
*
|
||||
* @param paramMap 表单数据
|
||||
* @param charset 编码,{@code null} 表示不encode键值对
|
||||
* @return url参数
|
||||
* @see #toParams(Map, Charset, boolean)
|
||||
*/
|
||||
public static String toParams(Map<String, ?> paramMap, Charset charset) {
|
||||
return toParams(paramMap, charset, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Map形式的Form表单数据转换为Url参数形式<br>
|
||||
* paramMap中如果key为空(null和"")会被忽略,如果value为null,会被做为空白符("")<br>
|
||||
* 会自动url编码键和值
|
||||
*
|
||||
* <pre>
|
||||
* key1=v1&key2=&key3=v3
|
||||
* </pre>
|
||||
*
|
||||
* @param paramMap 表单数据
|
||||
* @param charset 编码,null表示不encode键值对
|
||||
* @param isFormUrlEncoded 是否为x-www-form-urlencoded模式,此模式下空格会编码为'+'
|
||||
* @return url参数
|
||||
* @since 5.7.16
|
||||
*/
|
||||
public static String toParams(Map<String, ?> paramMap, Charset charset, boolean isFormUrlEncoded) {
|
||||
return UrlQuery.of(paramMap, isFormUrlEncoded).build(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对URL参数做编码,只编码键和值<br>
|
||||
* 提供的值可以是url附带参数,但是不能只是url
|
||||
*
|
||||
* <p>注意,此方法只能标准化整个URL,并不适合于单独编码参数值</p>
|
||||
*
|
||||
* @param urlWithParams url和参数,可以包含url本身,也可以单独参数
|
||||
* @param charset 编码
|
||||
* @return 编码后的url和参数
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public static String encodeParams(String urlWithParams, Charset charset) {
|
||||
if (StrUtil.isBlank(urlWithParams)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
|
||||
String urlPart = null; // url部分,不包括问号
|
||||
String paramPart; // 参数部分
|
||||
final int pathEndPos = urlWithParams.indexOf('?');
|
||||
if (pathEndPos > -1) {
|
||||
// url + 参数
|
||||
urlPart = StrUtil.subPre(urlWithParams, pathEndPos);
|
||||
paramPart = StrUtil.subSuf(urlWithParams, pathEndPos + 1);
|
||||
if (StrUtil.isBlank(paramPart)) {
|
||||
// 无参数,返回url
|
||||
return urlPart;
|
||||
}
|
||||
} else if (false == StrUtil.contains(urlWithParams, '=')) {
|
||||
// 无参数的URL
|
||||
return urlWithParams;
|
||||
} else {
|
||||
// 无URL的参数
|
||||
paramPart = urlWithParams;
|
||||
}
|
||||
|
||||
paramPart = normalizeParams(paramPart, charset);
|
||||
|
||||
return StrUtil.isBlank(urlPart) ? paramPart : urlPart + "?" + paramPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标准化参数字符串,即URL中?后的部分
|
||||
*
|
||||
* <p>注意,此方法只能标准化整个URL,并不适合于单独编码参数值</p>
|
||||
*
|
||||
* @param paramPart 参数字符串
|
||||
* @param charset 编码
|
||||
* @return 标准化的参数字符串
|
||||
* @since 4.5.2
|
||||
*/
|
||||
public static String normalizeParams(String paramPart, Charset charset) {
|
||||
if(StrUtil.isEmpty(paramPart)){
|
||||
return paramPart;
|
||||
}
|
||||
final StrBuilder builder = StrBuilder.create(paramPart.length() + 16);
|
||||
final int len = paramPart.length();
|
||||
String name = null;
|
||||
int pos = 0; // 未处理字符开始位置
|
||||
char c; // 当前字符
|
||||
int i; // 当前字符位置
|
||||
for (i = 0; i < len; i++) {
|
||||
c = paramPart.charAt(i);
|
||||
if (c == '=') { // 键值对的分界点
|
||||
if (null == name) {
|
||||
// 只有=前未定义name时被当作键值分界符,否则做为普通字符
|
||||
name = (pos == i) ? StrUtil.EMPTY : paramPart.substring(pos, i);
|
||||
pos = i + 1;
|
||||
}
|
||||
} else if (c == '&') { // 参数对的分界点
|
||||
if (pos != i) {
|
||||
if (null == name) {
|
||||
// 对于像&a&这类无参数值的字符串,我们将name为a的值设为""
|
||||
name = paramPart.substring(pos, i);
|
||||
builder.append(RFC3986.QUERY_PARAM_NAME.encode(name, charset)).append('=');
|
||||
} else {
|
||||
builder.append(RFC3986.QUERY_PARAM_NAME.encode(name, charset)).append('=')
|
||||
.append(RFC3986.QUERY_PARAM_VALUE.encode(paramPart.substring(pos, i), charset)).append('&');
|
||||
}
|
||||
name = null;
|
||||
}
|
||||
pos = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 结尾处理
|
||||
if (null != name) {
|
||||
builder.append(URLUtil.encodeQuery(name, charset)).append('=');
|
||||
}
|
||||
if (pos != i) {
|
||||
if (null == name && pos > 0) {
|
||||
builder.append('=');
|
||||
}
|
||||
builder.append(URLUtil.encodeQuery(paramPart.substring(pos, i), charset));
|
||||
}
|
||||
|
||||
// 以&结尾则去除之
|
||||
int lastIndex = builder.length() - 1;
|
||||
if ('&' == builder.charAt(lastIndex)) {
|
||||
builder.delTo(lastIndex);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将URL参数解析为Map(也可以解析Post中的键值对参数)
|
||||
*
|
||||
* @param paramsStr 参数字符串(或者带参数的Path)
|
||||
* @param charset 字符集
|
||||
* @return 参数Map
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public static Map<String, String> decodeParamMap(String paramsStr, Charset charset) {
|
||||
final Map<CharSequence, CharSequence> queryMap = UrlQuery.of(paramsStr, charset).getQueryMap();
|
||||
if (MapUtil.isEmpty(queryMap)) {
|
||||
return MapUtil.empty();
|
||||
}
|
||||
return Convert.toMap(String.class, String.class, queryMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将URL参数解析为Map(也可以解析Post中的键值对参数)
|
||||
*
|
||||
* @param paramsStr 参数字符串(或者带参数的Path)
|
||||
* @param charset 字符集
|
||||
* @return 参数Map
|
||||
*/
|
||||
public static Map<String, List<String>> decodeParams(String paramsStr, String charset) {
|
||||
return decodeParams(paramsStr, charset, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将URL参数解析为Map(也可以解析Post中的键值对参数)
|
||||
*
|
||||
* @param paramsStr 参数字符串(或者带参数的Path)
|
||||
* @param charset 字符集
|
||||
* @param isFormUrlEncoded 是否为x-www-form-urlencoded模式,此模式下空格会编码为'+'
|
||||
* @return 参数Map
|
||||
* @since 5.8.12
|
||||
*/
|
||||
public static Map<String, List<String>> decodeParams(String paramsStr, String charset, boolean isFormUrlEncoded) {
|
||||
return decodeParams(paramsStr, CharsetUtil.charset(charset), isFormUrlEncoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将URL QueryString参数解析为Map
|
||||
*
|
||||
* @param paramsStr 参数字符串(或者带参数的Path)
|
||||
* @param charset 字符集
|
||||
* @return 参数Map
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public static Map<String, List<String>> decodeParams(String paramsStr, Charset charset) {
|
||||
return decodeParams(paramsStr, charset, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将URL参数解析为Map(也可以解析Post中的键值对参数)
|
||||
*
|
||||
* @param paramsStr 参数字符串(或者带参数的Path)
|
||||
* @param charset 字符集
|
||||
* @param isFormUrlEncoded 是否为x-www-form-urlencoded模式,此模式下空格会编码为'+'
|
||||
* @return 参数Map
|
||||
*/
|
||||
public static Map<String, List<String>> decodeParams(String paramsStr, Charset charset, boolean isFormUrlEncoded) {
|
||||
final Map<CharSequence, CharSequence> queryMap =
|
||||
UrlQuery.of(paramsStr, charset, true, isFormUrlEncoded).getQueryMap();
|
||||
if (MapUtil.isEmpty(queryMap)) {
|
||||
return MapUtil.empty();
|
||||
}
|
||||
|
||||
final Map<String, List<String>> params = new LinkedHashMap<>();
|
||||
queryMap.forEach((key, value) -> {
|
||||
final List<String> values = params.computeIfAbsent(StrUtil.str(key), k -> new ArrayList<>(1));
|
||||
// 一般是一个参数
|
||||
values.add(StrUtil.str(value));
|
||||
});
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将表单数据加到URL中(用于GET表单提交)<br>
|
||||
* 表单的键值对会被url编码,但是url中原参数不会被编码
|
||||
*
|
||||
* @param url URL
|
||||
* @param form 表单数据
|
||||
* @param charset 编码
|
||||
* @param isEncodeParams 是否对键和值做转义处理
|
||||
* @return 合成后的URL
|
||||
*/
|
||||
public static String urlWithForm(String url, Map<String, Object> form, Charset charset, boolean isEncodeParams) {
|
||||
if (isEncodeParams && StrUtil.contains(url, '?')) {
|
||||
// 在需要编码的情况下,如果url中已经有部分参数,则编码之
|
||||
url = encodeParams(url, charset);
|
||||
}
|
||||
|
||||
// url和参数是分别编码的
|
||||
return urlWithForm(url, toParams(form, charset), charset, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将表单数据字符串加到URL中(用于GET表单提交)
|
||||
*
|
||||
* @param url URL
|
||||
* @param queryString 表单数据字符串
|
||||
* @param charset 编码
|
||||
* @param isEncode 是否对键和值做转义处理
|
||||
* @return 拼接后的字符串
|
||||
*/
|
||||
public static String urlWithForm(String url, String queryString, Charset charset, boolean isEncode) {
|
||||
if (StrUtil.isBlank(queryString)) {
|
||||
// 无额外参数
|
||||
if (StrUtil.contains(url, '?')) {
|
||||
// url中包含参数
|
||||
return isEncode ? encodeParams(url, charset) : url;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
// 始终有参数
|
||||
final StrBuilder urlBuilder = StrBuilder.create(url.length() + queryString.length() + 16);
|
||||
int qmIndex = url.indexOf('?');
|
||||
if (qmIndex > 0) {
|
||||
// 原URL带参数,则对这部分参数单独编码(如果选项为进行编码)
|
||||
urlBuilder.append(isEncode ? encodeParams(url, charset) : url);
|
||||
if (false == StrUtil.endWith(url, '&')) {
|
||||
// 已经带参数的情况下追加参数
|
||||
urlBuilder.append('&');
|
||||
}
|
||||
} else {
|
||||
// 原url无参数,则不做编码
|
||||
urlBuilder.append(url);
|
||||
if (qmIndex < 0) {
|
||||
// 无 '?' 追加之
|
||||
urlBuilder.append('?');
|
||||
}
|
||||
}
|
||||
urlBuilder.append(isEncode ? encodeParams(queryString, charset) : queryString);
|
||||
return urlBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Http连接的头信息中获得字符集<br>
|
||||
* 从ContentType中获取
|
||||
*
|
||||
* @param conn HTTP连接对象
|
||||
* @return 字符集
|
||||
*/
|
||||
public static String getCharset(HttpURLConnection conn) {
|
||||
if (conn == null) {
|
||||
return null;
|
||||
}
|
||||
return getCharset(conn.getContentType());
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Http连接的头信息中获得字符集<br>
|
||||
* 从ContentType中获取
|
||||
*
|
||||
* @param contentType Content-Type
|
||||
* @return 字符集
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public static String getCharset(String contentType) {
|
||||
if (StrUtil.isBlank(contentType)) {
|
||||
return null;
|
||||
}
|
||||
return ReUtil.get(CHARSET_PATTERN, contentType, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从流中读取内容<br>
|
||||
* 首先尝试使用charset编码读取内容(如果为空默认UTF-8),如果isGetCharsetFromContent为true,则通过正则在正文中获取编码信息,转换为指定编码;
|
||||
*
|
||||
* @param in 输入流
|
||||
* @param charset 字符集
|
||||
* @param isGetCharsetFromContent 是否从返回内容中获得编码信息
|
||||
* @return 内容
|
||||
*/
|
||||
public static String getString(InputStream in, Charset charset, boolean isGetCharsetFromContent) {
|
||||
final byte[] contentBytes = IoUtil.readBytes(in);
|
||||
return getString(contentBytes, charset, isGetCharsetFromContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从流中读取内容<br>
|
||||
* 首先尝试使用charset编码读取内容(如果为空默认UTF-8),如果isGetCharsetFromContent为true,则通过正则在正文中获取编码信息,转换为指定编码;
|
||||
*
|
||||
* @param contentBytes 内容byte数组
|
||||
* @param charset 字符集
|
||||
* @param isGetCharsetFromContent 是否从返回内容中获得编码信息
|
||||
* @return 内容
|
||||
*/
|
||||
public static String getString(byte[] contentBytes, Charset charset, boolean isGetCharsetFromContent) {
|
||||
if (null == contentBytes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null == charset) {
|
||||
charset = CharsetUtil.CHARSET_UTF_8;
|
||||
}
|
||||
String content = new String(contentBytes, charset);
|
||||
if (isGetCharsetFromContent) {
|
||||
final String charsetInContentStr = ReUtil.get(META_CHARSET_PATTERN, content, 1);
|
||||
if (StrUtil.isNotBlank(charsetInContentStr)) {
|
||||
Charset charsetInContent = null;
|
||||
try {
|
||||
charsetInContent = Charset.forName(charsetInContentStr);
|
||||
} catch (Exception e) {
|
||||
if (StrUtil.containsIgnoreCase(charsetInContentStr, "utf-8") || StrUtil.containsIgnoreCase(charsetInContentStr, "utf8")) {
|
||||
charsetInContent = CharsetUtil.CHARSET_UTF_8;
|
||||
} else if (StrUtil.containsIgnoreCase(charsetInContentStr, "gbk")) {
|
||||
charsetInContent = CharsetUtil.CHARSET_GBK;
|
||||
}
|
||||
// ignore
|
||||
}
|
||||
if (null != charsetInContent && false == charset.equals(charsetInContent)) {
|
||||
content = new String(contentBytes, charsetInContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件扩展名获得MimeType
|
||||
*
|
||||
* @param filePath 文件路径或文件名
|
||||
* @param defaultValue 当获取MimeType为null时的默认值
|
||||
* @return MimeType
|
||||
* @see FileUtil#getMimeType(String)
|
||||
* @since 4.6.5
|
||||
*/
|
||||
public static String getMimeType(String filePath, String defaultValue) {
|
||||
return ObjectUtil.defaultIfNull(getMimeType(filePath), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件扩展名获得MimeType
|
||||
*
|
||||
* @param filePath 文件路径或文件名
|
||||
* @return MimeType
|
||||
* @see FileUtil#getMimeType(String)
|
||||
*/
|
||||
public static String getMimeType(String filePath) {
|
||||
return FileUtil.getMimeType(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求参数的body中判断请求的Content-Type类型,支持的类型有:
|
||||
*
|
||||
* <pre>
|
||||
* 1. application/json
|
||||
* 1. application/xml
|
||||
* </pre>
|
||||
*
|
||||
* @param body 请求参数体
|
||||
* @return Content-Type类型,如果无法判断返回null
|
||||
* @see aiyh.utils.tool.cn.hutool.http.ContentType#get(String)
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static String getContentTypeByRequestBody(String body) {
|
||||
final aiyh.utils.tool.cn.hutool.http.ContentType contentType = ContentType.get(body);
|
||||
return (null == contentType) ? null : contentType.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建简易的Http服务器
|
||||
*
|
||||
* @param port 端口
|
||||
* @return {@link SimpleServer}
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public static SimpleServer createServer(int port) {
|
||||
return new SimpleServer(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建简单的账号秘密验证信息,构建后类似于:
|
||||
* <pre>
|
||||
* Basic YWxhZGRpbjpvcGVuc2VzYW1l
|
||||
* </pre>
|
||||
*
|
||||
* @param username 账号
|
||||
* @param password 密码
|
||||
* @param charset 编码(如果账号或密码中有非ASCII字符适用)
|
||||
* @return 密码验证信息
|
||||
* @since 5.4.6
|
||||
*/
|
||||
public static String buildBasicAuth(String username, String password, Charset charset) {
|
||||
final String data = username.concat(":").concat(password);
|
||||
return "Basic " + Base64.encode(data, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭Cookie
|
||||
*
|
||||
* @see GlobalCookieManager#setCookieManager(CookieManager)
|
||||
* @since 5.6.5
|
||||
*/
|
||||
public static void closeCookie() {
|
||||
GlobalCookieManager.setCookieManager(null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
/**
|
||||
* Http方法枚举
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public enum Method {
|
||||
GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE, CONNECT, PATCH
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.resource.MultiResource;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.resource.Resource;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.resource.StringResource;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Multipart/form-data输出流封装<br>
|
||||
* 遵循RFC2388规范
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public class MultipartOutputStream extends OutputStream {
|
||||
|
||||
private static final String CONTENT_DISPOSITION_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"\r\n";
|
||||
private static final String CONTENT_DISPOSITION_FILE_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"; filename=\"{}\"\r\n";
|
||||
|
||||
private static final String CONTENT_TYPE_FILE_TEMPLATE = "Content-Type: {}\r\n";
|
||||
|
||||
private final OutputStream out;
|
||||
private final Charset charset;
|
||||
private final String boundary;
|
||||
|
||||
private boolean isFinish;
|
||||
|
||||
/**
|
||||
* 构造,使用全局默认的边界字符串
|
||||
*
|
||||
* @param out HTTP写出流
|
||||
* @param charset 编码
|
||||
*/
|
||||
public MultipartOutputStream(OutputStream out, Charset charset) {
|
||||
this(out, charset, HttpGlobalConfig.getBoundary());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param out HTTP写出流
|
||||
* @param charset 编码
|
||||
* @param boundary 边界符
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public MultipartOutputStream(OutputStream out, Charset charset, String boundary) {
|
||||
this.out = out;
|
||||
this.charset = charset;
|
||||
this.boundary = boundary;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加Multipart表单的数据项<br>
|
||||
* <pre>
|
||||
* --分隔符(boundary)[换行]
|
||||
* Content-Disposition: form-data; name="参数名"[换行]
|
||||
* [换行]
|
||||
* 参数值[换行]
|
||||
* </pre>
|
||||
* <p>
|
||||
* 或者:
|
||||
*
|
||||
* <pre>
|
||||
* --分隔符(boundary)[换行]
|
||||
* Content-Disposition: form-data; name="表单名"; filename="文件名"[换行]
|
||||
* Content-Type: MIME类型[换行]
|
||||
* [换行]
|
||||
* 文件的二进制内容[换行]
|
||||
* </pre>
|
||||
*
|
||||
* @param formFieldName 表单名
|
||||
* @param value 值,可以是普通值、资源(如文件等)
|
||||
* @return this
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public MultipartOutputStream write(String formFieldName, Object value) throws IORuntimeException {
|
||||
// 多资源
|
||||
if (value instanceof MultiResource) {
|
||||
for (Resource subResource : (MultiResource) value) {
|
||||
write(formFieldName, subResource);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// --分隔符(boundary)[换行]
|
||||
beginPart();
|
||||
|
||||
if (value instanceof Resource) {
|
||||
appendResource(formFieldName, (Resource) value);
|
||||
} else {
|
||||
appendResource(formFieldName,
|
||||
new StringResource(Convert.toStr(value), null, this.charset));
|
||||
}
|
||||
|
||||
write(StrUtil.CRLF);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
this.out.write(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传表单结束
|
||||
*
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public void finish() throws IORuntimeException {
|
||||
if (!isFinish) {
|
||||
write(StrUtil.format("--{}--\r\n", boundary));
|
||||
this.isFinish = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
finish();
|
||||
IoUtil.close(this.out);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加Multipart表单的Resource数据项,支持包括{@link HttpResource}资源格式
|
||||
*
|
||||
* @param formFieldName 表单名
|
||||
* @param resource 资源
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
private void appendResource(String formFieldName, Resource resource) throws IORuntimeException {
|
||||
final String fileName = resource.getName();
|
||||
|
||||
// Content-Disposition
|
||||
if (null == fileName) {
|
||||
// Content-Disposition: form-data; name="参数名"[换行]
|
||||
write(StrUtil.format(CONTENT_DISPOSITION_TEMPLATE, formFieldName));
|
||||
} else {
|
||||
// Content-Disposition: form-data; name="参数名"; filename="文件名"[换行]
|
||||
write(StrUtil.format(CONTENT_DISPOSITION_FILE_TEMPLATE, formFieldName, fileName));
|
||||
}
|
||||
|
||||
// Content-Type
|
||||
if (resource instanceof HttpResource) {
|
||||
final String contentType = ((HttpResource) resource).getContentType();
|
||||
if (StrUtil.isNotBlank(contentType)) {
|
||||
// Content-Type: 类型[换行]
|
||||
write(StrUtil.format(CONTENT_TYPE_FILE_TEMPLATE, contentType));
|
||||
}
|
||||
} else if (StrUtil.isNotEmpty(fileName)) {
|
||||
// 根据name的扩展名指定互联网媒体类型,默认二进制流数据
|
||||
write(StrUtil.format(CONTENT_TYPE_FILE_TEMPLATE,
|
||||
HttpUtil.getMimeType(fileName, ContentType.OCTET_STREAM.getValue())));
|
||||
}
|
||||
|
||||
// 内容
|
||||
write("\r\n");
|
||||
resource.writeTo(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* part开始,写出:<br>
|
||||
* <pre>
|
||||
* --分隔符(boundary)[换行]
|
||||
* </pre>
|
||||
*/
|
||||
private void beginPart() {
|
||||
// --分隔符(boundary)[换行]
|
||||
write("--", boundary, StrUtil.CRLF);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出对象
|
||||
*
|
||||
* @param objs 写出的对象(转换为字符串)
|
||||
*/
|
||||
private void write(Object... objs) {
|
||||
IoUtil.write(this, this.charset, false, objs);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
package aiyh.utils.tool.cn.hutool.http;
|
||||
|
||||
/**
|
||||
* 返回状态码
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
interface Status {
|
||||
/**
|
||||
* HTTP Status-Code 200: OK.
|
||||
*/
|
||||
int HTTP_OK = 200;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 201: Created.
|
||||
*/
|
||||
int HTTP_CREATED = 201;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 202: Accepted.
|
||||
*/
|
||||
int HTTP_ACCEPTED = 202;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 203: Non-Authoritative Information.
|
||||
*/
|
||||
int HTTP_NOT_AUTHORITATIVE = 203;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 204: No Content.
|
||||
*/
|
||||
int HTTP_NO_CONTENT = 204;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 205: Reset Content.
|
||||
*/
|
||||
int HTTP_RESET = 205;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 206: Partial Content.
|
||||
*/
|
||||
int HTTP_PARTIAL = 206;
|
||||
|
||||
/* 3XX: relocation/redirect */
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 300: Multiple Choices.
|
||||
*/
|
||||
int HTTP_MULT_CHOICE = 300;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 301: Moved Permanently.
|
||||
*/
|
||||
int HTTP_MOVED_PERM = 301;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 302: Temporary Redirect.
|
||||
*/
|
||||
int HTTP_MOVED_TEMP = 302;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 303: See Other.
|
||||
*/
|
||||
int HTTP_SEE_OTHER = 303;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 304: Not Modified.
|
||||
*/
|
||||
int HTTP_NOT_MODIFIED = 304;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 305: Use Proxy.
|
||||
*/
|
||||
int HTTP_USE_PROXY = 305;
|
||||
|
||||
/* 4XX: client error */
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 400: Bad Request.
|
||||
*/
|
||||
int HTTP_BAD_REQUEST = 400;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 401: Unauthorized.
|
||||
*/
|
||||
int HTTP_UNAUTHORIZED = 401;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 402: Payment Required.
|
||||
*/
|
||||
int HTTP_PAYMENT_REQUIRED = 402;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 403: Forbidden.
|
||||
*/
|
||||
int HTTP_FORBIDDEN = 403;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 404: Not Found.
|
||||
*/
|
||||
int HTTP_NOT_FOUND = 404;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 405: Method Not Allowed.
|
||||
*/
|
||||
int HTTP_BAD_METHOD = 405;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 406: Not Acceptable.
|
||||
*/
|
||||
int HTTP_NOT_ACCEPTABLE = 406;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 407: Proxy Authentication Required.
|
||||
*/
|
||||
int HTTP_PROXY_AUTH = 407;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 408: Request Time-Out.
|
||||
*/
|
||||
int HTTP_CLIENT_TIMEOUT = 408;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 409: Conflict.
|
||||
*/
|
||||
int HTTP_CONFLICT = 409;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 410: Gone.
|
||||
*/
|
||||
int HTTP_GONE = 410;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 411: Length Required.
|
||||
*/
|
||||
int HTTP_LENGTH_REQUIRED = 411;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 412: Precondition Failed.
|
||||
*/
|
||||
int HTTP_PRECON_FAILED = 412;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 413: Request Entity Too Large.
|
||||
*/
|
||||
int HTTP_ENTITY_TOO_LARGE = 413;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 414: Request-URI Too Large.
|
||||
*/
|
||||
int HTTP_REQ_TOO_LONG = 414;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 415: Unsupported Media Type.
|
||||
*/
|
||||
int HTTP_UNSUPPORTED_TYPE = 415;
|
||||
|
||||
/* 5XX: server error */
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 500: Internal Server Error.
|
||||
*/
|
||||
int HTTP_INTERNAL_ERROR = 500;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 501: Not Implemented.
|
||||
*/
|
||||
int HTTP_NOT_IMPLEMENTED = 501;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 502: Bad Gateway.
|
||||
*/
|
||||
int HTTP_BAD_GATEWAY = 502;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 503: Service Unavailable.
|
||||
*/
|
||||
int HTTP_UNAVAILABLE = 503;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 504: Gateway Timeout.
|
||||
*/
|
||||
int HTTP_GATEWAY_TIMEOUT = 504;
|
||||
|
||||
/**
|
||||
* HTTP Status-Code 505: HTTP Version Not Supported.
|
||||
*/
|
||||
int HTTP_VERSION = 505;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.body;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* bytes类型的Http request body,主要发送编码后的表单数据或rest body(如JSON或XML)
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public class BytesBody implements RequestBody {
|
||||
|
||||
private final byte[] content;
|
||||
|
||||
/**
|
||||
* 创建 Http request body
|
||||
*
|
||||
* @param content body内容,编码后
|
||||
* @return BytesBody
|
||||
*/
|
||||
public static BytesBody create(byte[] content) {
|
||||
return new BytesBody(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param content Body内容,编码后
|
||||
*/
|
||||
public BytesBody(byte[] content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(OutputStream out) {
|
||||
IoUtil.write(out, false, content);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.body;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.net.url.UrlQuery;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* application/x-www-form-urlencoded 类型请求body封装
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public class FormUrlEncodedBody extends BytesBody {
|
||||
|
||||
/**
|
||||
* 创建 Http request body
|
||||
*
|
||||
* @param form 表单
|
||||
* @param charset 编码
|
||||
* @return FormUrlEncodedBody
|
||||
*/
|
||||
public static FormUrlEncodedBody create(Map<String, Object> form, Charset charset) {
|
||||
return new FormUrlEncodedBody(form, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param form 表单
|
||||
* @param charset 编码
|
||||
*/
|
||||
public FormUrlEncodedBody(Map<String, Object> form, Charset charset) {
|
||||
super(StrUtil.bytes(UrlQuery.of(form, true).build(charset), charset));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.body;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.map.MapUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.ContentType;
|
||||
import aiyh.utils.tool.cn.hutool.http.HttpGlobalConfig;
|
||||
import aiyh.utils.tool.cn.hutool.http.MultipartOutputStream;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Multipart/form-data数据的请求体封装<br>
|
||||
* 遵循RFC2388规范
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.3.5
|
||||
*/
|
||||
public class MultipartBody implements RequestBody {
|
||||
|
||||
private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary=";
|
||||
|
||||
/**
|
||||
* 存储表单数据
|
||||
*/
|
||||
private final Map<String, Object> form;
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final Charset charset;
|
||||
/**
|
||||
* 边界
|
||||
*/
|
||||
private final String boundary = HttpGlobalConfig.getBoundary();
|
||||
|
||||
/**
|
||||
* 根据已有表单内容,构建MultipartBody
|
||||
*
|
||||
* @param form 表单
|
||||
* @param charset 编码
|
||||
* @return MultipartBody
|
||||
*/
|
||||
public static MultipartBody create(Map<String, Object> form, Charset charset) {
|
||||
return new MultipartBody(form, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Multipart的Content-Type类型
|
||||
*
|
||||
* @return Multipart的Content-Type类型
|
||||
*/
|
||||
public String getContentType() {
|
||||
return CONTENT_TYPE_MULTIPART_PREFIX + boundary;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param form 表单
|
||||
* @param charset 编码
|
||||
*/
|
||||
public MultipartBody(Map<String, Object> form, Charset charset) {
|
||||
this.form = form;
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出Multiparty数据,不关闭流
|
||||
*
|
||||
* @param out out流
|
||||
*/
|
||||
@Override
|
||||
public void write(OutputStream out) {
|
||||
final MultipartOutputStream stream = new MultipartOutputStream(out, this.charset, this.boundary);
|
||||
if (MapUtil.isNotEmpty(this.form)) {
|
||||
this.form.forEach(stream::write);
|
||||
}
|
||||
stream.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
write(out);
|
||||
return IoUtil.toStr(out, this.charset);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.body;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* 定义请求体接口
|
||||
*/
|
||||
public interface RequestBody {
|
||||
|
||||
/**
|
||||
* 写出数据,不关闭流
|
||||
*
|
||||
* @param out out流
|
||||
*/
|
||||
void write(OutputStream out);
|
||||
|
||||
/**
|
||||
* 写出并关闭{@link OutputStream}
|
||||
*
|
||||
* @param out {@link OutputStream}
|
||||
* @since 5.7.17
|
||||
*/
|
||||
default void writeClose(OutputStream out) {
|
||||
try {
|
||||
write(out);
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* 请求体封装实现
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http.body;
|
|
@ -0,0 +1,109 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.cookie;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.URLUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.HttpConnection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 全局Cookie管理器,只针对Hutool请求有效
|
||||
*
|
||||
* @author Looly
|
||||
* @since 4.5.15
|
||||
*/
|
||||
public class GlobalCookieManager {
|
||||
|
||||
/** Cookie管理 */
|
||||
private static CookieManager cookieManager;
|
||||
|
||||
static {
|
||||
cookieManager = new CookieManager(new ThreadLocalCookieStore(), CookiePolicy.ACCEPT_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义{@link CookieManager}
|
||||
*
|
||||
* @param customCookieManager 自定义的{@link CookieManager}
|
||||
*/
|
||||
public static void setCookieManager(CookieManager customCookieManager) {
|
||||
cookieManager = customCookieManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局{@link CookieManager}
|
||||
*
|
||||
* @return {@link CookieManager}
|
||||
*/
|
||||
public static CookieManager getCookieManager() {
|
||||
return cookieManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定域名下所有Cookie信息
|
||||
*
|
||||
* @param conn HTTP连接
|
||||
* @return Cookie信息列表
|
||||
* @since 4.6.9
|
||||
*/
|
||||
public static List<HttpCookie> getCookies(aiyh.utils.tool.cn.hutool.http.HttpConnection conn) {
|
||||
return cookieManager.getCookieStore().get(getURI(conn));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将本地存储的Cookie信息附带到Http请求中,不覆盖用户定义好的Cookie
|
||||
*
|
||||
* @param conn {@link aiyh.utils.tool.cn.hutool.http.HttpConnection}
|
||||
*/
|
||||
public static void add(aiyh.utils.tool.cn.hutool.http.HttpConnection conn) {
|
||||
if (null == cookieManager) {
|
||||
// 全局Cookie管理器关闭
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, List<String>> cookieHeader;
|
||||
try {
|
||||
cookieHeader = cookieManager.get(getURI(conn), new HashMap<>(0));
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
|
||||
// 不覆盖模式回填Cookie头,这样用户定义的Cookie将优先
|
||||
conn.header(cookieHeader, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储响应的Cookie信息到本地
|
||||
*
|
||||
* @param conn {@link aiyh.utils.tool.cn.hutool.http.HttpConnection}
|
||||
*/
|
||||
public static void store(aiyh.utils.tool.cn.hutool.http.HttpConnection conn) {
|
||||
if (null == cookieManager) {
|
||||
// 全局Cookie管理器关闭
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
cookieManager.put(getURI(conn), conn.headers());
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取连接的URL中URI信息
|
||||
*
|
||||
* @param conn HttpConnection
|
||||
* @return URI
|
||||
*/
|
||||
private static URI getURI(HttpConnection conn) {
|
||||
return URLUtil.toURI(conn.getUrl());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.cookie;
|
||||
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookieStore;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 线程隔离的Cookie存储。多线程环境下Cookie隔离使用,防止Cookie覆盖<br>
|
||||
* <p>
|
||||
* 见:https://stackoverflow.com/questions/16305486/cookiemanager-for-multiple-threads
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.1.18
|
||||
*/
|
||||
public class ThreadLocalCookieStore implements CookieStore {
|
||||
|
||||
private final static ThreadLocal<CookieStore> STORES = new ThreadLocal<CookieStore>() {
|
||||
@Override
|
||||
protected synchronized CookieStore initialValue() {
|
||||
/* InMemoryCookieStore */
|
||||
return (new CookieManager()).getCookieStore();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取本线程下的CookieStore
|
||||
*
|
||||
* @return CookieStore
|
||||
*/
|
||||
public CookieStore getCookieStore() {
|
||||
return STORES.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除当前线程的Cookie
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public ThreadLocalCookieStore removeCurrent() {
|
||||
STORES.remove();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(URI uri, HttpCookie cookie) {
|
||||
getCookieStore().add(uri, cookie);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HttpCookie> get(URI uri) {
|
||||
return getCookieStore().get(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HttpCookie> getCookies() {
|
||||
return getCookieStore().getCookies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URI> getURIs() {
|
||||
return getCookieStore().getURIs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(URI uri, HttpCookie cookie) {
|
||||
return getCookieStore().remove(uri, cookie);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll() {
|
||||
return getCookieStore().removeAll();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* 自定义Cookie
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http.cookie;
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* Hutool-http针对JDK的HttpUrlConnection做一层封装,简化了HTTPS请求、文件上传、Cookie记忆等操作,使Http请求变得无比简单。
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http;
|
|
@ -0,0 +1,57 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.server;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.CharsetUtil;
|
||||
import com.sun.net.httpserver.HttpContext;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* HttpServer公用对象,提供HttpExchange包装和公用方法
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public class HttpServerBase implements Closeable {
|
||||
|
||||
final static Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8;
|
||||
|
||||
final HttpExchange httpExchange;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param httpExchange {@link HttpExchange}
|
||||
*/
|
||||
public HttpServerBase(HttpExchange httpExchange) {
|
||||
this.httpExchange = httpExchange;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取{@link HttpExchange}对象
|
||||
*
|
||||
* @return {@link HttpExchange}对象
|
||||
*/
|
||||
public HttpExchange getHttpExchange() {
|
||||
return this.httpExchange;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取{@link HttpContext}
|
||||
*
|
||||
* @return {@link HttpContext}
|
||||
* @since 5.5.7
|
||||
*/
|
||||
public HttpContext getHttpContext() {
|
||||
return getHttpExchange().getHttpContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用{@link HttpExchange#close()},关闭请求流和响应流
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
this.httpExchange.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,442 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.server;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.map.CaseInsensitiveMap;
|
||||
import aiyh.utils.tool.cn.hutool.core.map.multi.ListValueMap;
|
||||
import aiyh.utils.tool.cn.hutool.core.net.NetUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.net.multipart.MultipartFormData;
|
||||
import aiyh.utils.tool.cn.hutool.core.net.multipart.UploadSetting;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.CharsetUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.Header;
|
||||
import aiyh.utils.tool.cn.hutool.http.HttpUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.Method;
|
||||
import aiyh.utils.tool.cn.hutool.http.useragent.UserAgent;
|
||||
import aiyh.utils.tool.cn.hutool.http.useragent.UserAgentUtil;
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Http请求对象,对{@link HttpExchange}封装
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public class HttpServerRequest extends HttpServerBase {
|
||||
|
||||
private Map<String, HttpCookie> cookieCache;
|
||||
private ListValueMap<String, String> paramsCache;
|
||||
private MultipartFormData multipartFormDataCache;
|
||||
private Charset charsetCache;
|
||||
private byte[] bodyCache;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param httpExchange {@link HttpExchange}
|
||||
*/
|
||||
public HttpServerRequest(HttpExchange httpExchange) {
|
||||
super(httpExchange);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得Http Method
|
||||
*
|
||||
* @return Http Method
|
||||
*/
|
||||
public String getMethod() {
|
||||
return this.httpExchange.getRequestMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为GET请求
|
||||
*
|
||||
* @return 是否为GET请求
|
||||
*/
|
||||
public boolean isGetMethod() {
|
||||
return aiyh.utils.tool.cn.hutool.http.Method.GET.name().equalsIgnoreCase(getMethod());
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为POST请求
|
||||
*
|
||||
* @return 是否为POST请求
|
||||
*/
|
||||
public boolean isPostMethod() {
|
||||
return Method.POST.name().equalsIgnoreCase(getMethod());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得请求URI
|
||||
*
|
||||
* @return 请求URI
|
||||
*/
|
||||
public URI getURI() {
|
||||
return this.httpExchange.getRequestURI();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得请求路径Path
|
||||
*
|
||||
* @return 请求路径
|
||||
*/
|
||||
public String getPath() {
|
||||
return getURI().getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求参数
|
||||
*
|
||||
* @return 参数字符串
|
||||
*/
|
||||
public String getQuery() {
|
||||
return getURI().getQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得请求header中的信息
|
||||
*
|
||||
* @return header值
|
||||
*/
|
||||
public Headers getHeaders() {
|
||||
return this.httpExchange.getRequestHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得请求header中的信息
|
||||
*
|
||||
* @param headerKey 头信息的KEY
|
||||
* @return header值
|
||||
*/
|
||||
public String getHeader(aiyh.utils.tool.cn.hutool.http.Header headerKey) {
|
||||
return getHeader(headerKey.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得请求header中的信息
|
||||
*
|
||||
* @param headerKey 头信息的KEY
|
||||
* @return header值
|
||||
*/
|
||||
public String getHeader(String headerKey) {
|
||||
return getHeaders().getFirst(headerKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得请求header中的信息
|
||||
*
|
||||
* @param headerKey 头信息的KEY
|
||||
* @param charset 字符集
|
||||
* @return header值
|
||||
*/
|
||||
public String getHeader(String headerKey, Charset charset) {
|
||||
final String header = getHeader(headerKey);
|
||||
if (null != header) {
|
||||
return CharsetUtil.convert(header, CharsetUtil.CHARSET_ISO_8859_1, charset);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Content-Type头信息
|
||||
*
|
||||
* @return Content-Type头信息
|
||||
*/
|
||||
public String getContentType() {
|
||||
return getHeader(aiyh.utils.tool.cn.hutool.http.Header.CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取编码,获取失败默认使用UTF-8,获取规则如下:
|
||||
*
|
||||
* <pre>
|
||||
* 1、从Content-Type头中获取编码,类似于:text/html;charset=utf-8
|
||||
* </pre>
|
||||
*
|
||||
* @return 编码,默认UTF-8
|
||||
*/
|
||||
public Charset getCharset() {
|
||||
if (null == this.charsetCache) {
|
||||
final String contentType = getContentType();
|
||||
final String charsetStr = aiyh.utils.tool.cn.hutool.http.HttpUtil.getCharset(contentType);
|
||||
this.charsetCache = CharsetUtil.parse(charsetStr, DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
return this.charsetCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得User-Agent
|
||||
*
|
||||
* @return User-Agent字符串
|
||||
*/
|
||||
public String getUserAgentStr() {
|
||||
return getHeader(aiyh.utils.tool.cn.hutool.http.Header.USER_AGENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得User-Agent,未识别返回null
|
||||
*
|
||||
* @return User-Agent字符串,未识别返回null
|
||||
*/
|
||||
public UserAgent getUserAgent() {
|
||||
return UserAgentUtil.parse(getUserAgentStr());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得Cookie信息字符串
|
||||
*
|
||||
* @return cookie字符串
|
||||
*/
|
||||
public String getCookiesStr() {
|
||||
return getHeader(Header.COOKIE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得Cookie信息列表
|
||||
*
|
||||
* @return Cookie信息列表
|
||||
*/
|
||||
public Collection<HttpCookie> getCookies() {
|
||||
return getCookieMap().values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得Cookie信息Map,键为Cookie名,值为HttpCookie对象
|
||||
*
|
||||
* @return Cookie信息Map
|
||||
*/
|
||||
public Map<String, HttpCookie> getCookieMap() {
|
||||
if (null == this.cookieCache) {
|
||||
cookieCache = Collections.unmodifiableMap(CollUtil.toMap(
|
||||
NetUtil.parseCookies(getCookiesStr()),
|
||||
new CaseInsensitiveMap<>(),
|
||||
HttpCookie::getName));
|
||||
}
|
||||
return cookieCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定Cookie名对应的HttpCookie对象
|
||||
*
|
||||
* @param cookieName Cookie名
|
||||
* @return HttpCookie对象
|
||||
*/
|
||||
public HttpCookie getCookie(String cookieName) {
|
||||
return getCookieMap().get(cookieName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为Multipart类型表单,此类型表单用于文件上传
|
||||
*
|
||||
* @return 是否为Multipart类型表单,此类型表单用于文件上传
|
||||
*/
|
||||
public boolean isMultipart() {
|
||||
if (!isPostMethod()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String contentType = getContentType();
|
||||
if (StrUtil.isBlank(contentType)) {
|
||||
return false;
|
||||
}
|
||||
return contentType.toLowerCase().startsWith("multipart/");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求体文本,可以是form表单、json、xml等任意内容<br>
|
||||
* 使用{@link #getCharset()}判断编码,判断失败使用UTF-8编码
|
||||
*
|
||||
* @return 请求
|
||||
*/
|
||||
public String getBody() {
|
||||
return getBody(getCharset());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求体文本,可以是form表单、json、xml等任意内容
|
||||
*
|
||||
* @param charset 编码
|
||||
* @return 请求
|
||||
*/
|
||||
public String getBody(Charset charset) {
|
||||
return StrUtil.str(getBodyBytes(), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取body的bytes数组
|
||||
*
|
||||
* @return body的bytes数组
|
||||
*/
|
||||
public byte[] getBodyBytes() {
|
||||
if (null == this.bodyCache) {
|
||||
this.bodyCache = IoUtil.readBytes(getBodyStream(), true);
|
||||
}
|
||||
return this.bodyCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求体的流,流中可以读取请求内容,包括请求表单数据或文件上传数据
|
||||
*
|
||||
* @return 流
|
||||
*/
|
||||
public InputStream getBodyStream() {
|
||||
return this.httpExchange.getRequestBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定名称的参数值,取第一个值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 参数值
|
||||
* @since 5.5.8
|
||||
*/
|
||||
public String getParam(String name) {
|
||||
return getParams().get(name, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定名称的参数值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 参数值
|
||||
* @since 5.5.8
|
||||
*/
|
||||
public List<String> getParams(String name) {
|
||||
return getParams().get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数Map
|
||||
*
|
||||
* @return 参数map
|
||||
*/
|
||||
public ListValueMap<String, String> getParams() {
|
||||
if (null == this.paramsCache) {
|
||||
this.paramsCache = new ListValueMap<>();
|
||||
final Charset charset = getCharset();
|
||||
|
||||
// 解析URL中的参数
|
||||
final String query = getQuery();
|
||||
if (StrUtil.isNotBlank(query)) {
|
||||
this.paramsCache.putAll(aiyh.utils.tool.cn.hutool.http.HttpUtil.decodeParams(query, charset, false));
|
||||
}
|
||||
|
||||
// 解析multipart中的参数
|
||||
if (isMultipart()) {
|
||||
this.paramsCache.putAll(getMultipart().getParamListMap());
|
||||
} else {
|
||||
// 解析body中的参数
|
||||
final String body = getBody();
|
||||
if (StrUtil.isNotBlank(body)) {
|
||||
this.paramsCache.putAll(HttpUtil.decodeParams(body, charset, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.paramsCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端IP
|
||||
*
|
||||
* <p>
|
||||
* 默认检测的Header:
|
||||
*
|
||||
* <pre>
|
||||
* 1、X-Forwarded-For
|
||||
* 2、X-Real-IP
|
||||
* 3、Proxy-Client-IP
|
||||
* 4、WL-Proxy-Client-IP
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* otherHeaderNames参数用于自定义检测的Header<br>
|
||||
* 需要注意的是,使用此方法获取的客户IP地址必须在Http服务器(例如Nginx)中配置头信息,否则容易造成IP伪造。
|
||||
* </p>
|
||||
*
|
||||
* @param otherHeaderNames 其他自定义头文件,通常在Http服务器(例如Nginx)中配置
|
||||
* @return IP地址
|
||||
*/
|
||||
public String getClientIP(String... otherHeaderNames) {
|
||||
String[] headers = {"X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"};
|
||||
if (ArrayUtil.isNotEmpty(otherHeaderNames)) {
|
||||
headers = ArrayUtil.addAll(headers, otherHeaderNames);
|
||||
}
|
||||
|
||||
return getClientIPByHeader(headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端IP
|
||||
*
|
||||
* <p>
|
||||
* headerNames参数用于自定义检测的Header<br>
|
||||
* 需要注意的是,使用此方法获取的客户IP地址必须在Http服务器(例如Nginx)中配置头信息,否则容易造成IP伪造。
|
||||
* </p>
|
||||
*
|
||||
* @param headerNames 自定义头,通常在Http服务器(例如Nginx)中配置
|
||||
* @return IP地址
|
||||
* @since 4.4.1
|
||||
*/
|
||||
public String getClientIPByHeader(String... headerNames) {
|
||||
String ip;
|
||||
for (String header : headerNames) {
|
||||
ip = getHeader(header);
|
||||
if (!NetUtil.isUnknown(ip)) {
|
||||
return NetUtil.getMultistageReverseProxyIp(ip);
|
||||
}
|
||||
}
|
||||
|
||||
ip = this.httpExchange.getRemoteAddress().getHostName();
|
||||
return NetUtil.getMultistageReverseProxyIp(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得MultiPart表单内容,多用于获得上传的文件
|
||||
*
|
||||
* @return MultipartFormData
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public MultipartFormData getMultipart() throws IORuntimeException {
|
||||
if (null == this.multipartFormDataCache) {
|
||||
this.multipartFormDataCache = parseMultipart(new UploadSetting());
|
||||
}
|
||||
return this.multipartFormDataCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得multipart/form-data 表单内容<br>
|
||||
* 包括文件和普通表单数据<br>
|
||||
* 在同一次请求中,此方法只能被执行一次!
|
||||
*
|
||||
* @param uploadSetting 上传文件的设定,包括最大文件大小、保存在内存的边界大小、临时目录、扩展名限定等
|
||||
* @return MultiPart表单
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public MultipartFormData parseMultipart(UploadSetting uploadSetting) throws IORuntimeException {
|
||||
final MultipartFormData formData = new MultipartFormData(uploadSetting);
|
||||
try {
|
||||
formData.parseRequestStream(getBodyStream(), getCharset());
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
|
||||
return formData;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,429 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.server;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.FileUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.URLUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.ContentType;
|
||||
import aiyh.utils.tool.cn.hutool.http.Header;
|
||||
import aiyh.utils.tool.cn.hutool.http.HttpStatus;
|
||||
import aiyh.utils.tool.cn.hutool.http.HttpUtil;
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Http响应对象,用于写出数据到客户端
|
||||
*/
|
||||
public class HttpServerResponse extends HttpServerBase {
|
||||
|
||||
private Charset charset;
|
||||
/**
|
||||
* 是否已经发送了Http状态码,如果没有,提前写出状态码
|
||||
*/
|
||||
private boolean isSendCode;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param httpExchange {@link HttpExchange}
|
||||
*/
|
||||
public HttpServerResponse(HttpExchange httpExchange) {
|
||||
super(httpExchange);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP状态码,Content-Length为0不定长度,会输出Transfer-encoding: chunked
|
||||
*
|
||||
* @param httpStatusCode HTTP状态码,见HttpStatus
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse send(int httpStatusCode) {
|
||||
return send(httpStatusCode, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送成功状态码
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse sendOk() {
|
||||
return send(aiyh.utils.tool.cn.hutool.http.HttpStatus.HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送成功状态码
|
||||
*
|
||||
* @param bodyLength 响应体长度,默认0表示不定长度,会输出Transfer-encoding: chunked
|
||||
* @return this
|
||||
* @since 5.5.7
|
||||
*/
|
||||
public HttpServerResponse sendOk(int bodyLength) {
|
||||
return send(aiyh.utils.tool.cn.hutool.http.HttpStatus.HTTP_OK, bodyLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送404错误页
|
||||
*
|
||||
* @param content 错误页页面内容,默认text/html类型
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse send404(String content) {
|
||||
return sendError(HttpStatus.HTTP_NOT_FOUND, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送错误页
|
||||
*
|
||||
* @param errorCode HTTP错误状态码,见HttpStatus
|
||||
* @param content 错误页页面内容,默认text/html类型
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse sendError(int errorCode, String content) {
|
||||
send(errorCode);
|
||||
setContentType(aiyh.utils.tool.cn.hutool.http.ContentType.TEXT_HTML.toString());
|
||||
return write(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP状态码
|
||||
*
|
||||
* @param httpStatusCode HTTP状态码,见HttpStatus
|
||||
* @param bodyLength 响应体长度,默认0表示不定长度,会输出Transfer-encoding: chunked
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse send(int httpStatusCode, long bodyLength) {
|
||||
if (this.isSendCode) {
|
||||
throw new IORuntimeException("Http status code has been send!");
|
||||
}
|
||||
|
||||
try {
|
||||
this.httpExchange.sendResponseHeaders(httpStatusCode, bodyLength);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
|
||||
this.isSendCode = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得所有响应头,获取后可以添加新的响应头
|
||||
*
|
||||
* @return 响应头
|
||||
*/
|
||||
public Headers getHeaders() {
|
||||
return this.httpExchange.getResponseHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加响应头,如果已经存在,则追加
|
||||
*
|
||||
* @param header 头key
|
||||
* @param value 值
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse addHeader(String header, String value) {
|
||||
getHeaders().add(header, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应头,如果已经存在,则覆盖
|
||||
*
|
||||
* @param header 头key
|
||||
* @param value 值
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse setHeader(aiyh.utils.tool.cn.hutool.http.Header header, String value) {
|
||||
return setHeader(header.getValue(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应头,如果已经存在,则覆盖
|
||||
*
|
||||
* @param header 头key
|
||||
* @param value 值
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse setHeader(String header, String value) {
|
||||
getHeaders().set(header, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应头,如果已经存在,则覆盖
|
||||
*
|
||||
* @param header 头key
|
||||
* @param value 值列表
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse setHeader(String header, List<String> value) {
|
||||
getHeaders().put(header, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置所有响应头,如果已经存在,则覆盖
|
||||
*
|
||||
* @param headers 响应头map
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse setHeaders(Map<String, List<String>> headers) {
|
||||
getHeaders().putAll(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Content-Type头,类似于:text/html;charset=utf-8<br>
|
||||
* 如果用户传入的信息无charset信息,自动根据charset补充,charset设置见{@link #setCharset(Charset)}
|
||||
*
|
||||
* @param contentType Content-Type头内容
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse setContentType(String contentType) {
|
||||
if (null != contentType && null != this.charset) {
|
||||
if (!contentType.contains(";charset=")) {
|
||||
contentType = ContentType.build(contentType, this.charset);
|
||||
}
|
||||
}
|
||||
|
||||
return setHeader(aiyh.utils.tool.cn.hutool.http.Header.CONTENT_TYPE, contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Content-Length头
|
||||
*
|
||||
* @param contentLength Content-Length头内容
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse setContentLength(long contentLength) {
|
||||
return setHeader(aiyh.utils.tool.cn.hutool.http.Header.CONTENT_LENGTH, String.valueOf(contentLength));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应的编码
|
||||
*
|
||||
* @param charset 编码
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse setCharset(Charset charset) {
|
||||
this.charset = charset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置属性
|
||||
*
|
||||
* @param name 属性名
|
||||
* @param value 属性值
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse setAttr(String name, Object value) {
|
||||
this.httpExchange.setAttribute(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应数据流
|
||||
*
|
||||
* @return 响应数据流
|
||||
*/
|
||||
public OutputStream getOut() {
|
||||
if (!this.isSendCode) {
|
||||
sendOk();
|
||||
}
|
||||
return this.httpExchange.getResponseBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应数据流
|
||||
*
|
||||
* @return 响应数据流
|
||||
*/
|
||||
public PrintWriter getWriter() {
|
||||
final Charset charset = ObjectUtil.defaultIfNull(this.charset, DEFAULT_CHARSET);
|
||||
return new PrintWriter(new OutputStreamWriter(getOut(), charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出数据到客户端
|
||||
*
|
||||
* @param data 数据
|
||||
* @param contentType Content-Type类型
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse write(String data, String contentType) {
|
||||
setContentType(contentType);
|
||||
return write(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出数据到客户端
|
||||
*
|
||||
* @param data 数据
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse write(String data) {
|
||||
final Charset charset = ObjectUtil.defaultIfNull(this.charset, DEFAULT_CHARSET);
|
||||
return write(StrUtil.bytes(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出数据到客户端
|
||||
*
|
||||
* @param data 数据
|
||||
* @param contentType 返回的类型
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse write(byte[] data, String contentType) {
|
||||
setContentType(contentType);
|
||||
return write(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出数据到客户端
|
||||
*
|
||||
* @param data 数据
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse write(byte[] data) {
|
||||
final ByteArrayInputStream in = new ByteArrayInputStream(data);
|
||||
return write(in, in.available());
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数据给客户端
|
||||
*
|
||||
* @param in 需要返回客户端的内容
|
||||
* @param contentType 返回的类型
|
||||
* @return this
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public HttpServerResponse write(InputStream in, String contentType) {
|
||||
return write(in, 0, contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数据给客户端
|
||||
*
|
||||
* @param in 需要返回客户端的内容
|
||||
* @param length 内容长度,默认0表示不定长度,会输出Transfer-encoding: chunked
|
||||
* @param contentType 返回的类型
|
||||
* @return this
|
||||
* @since 5.2.7
|
||||
*/
|
||||
public HttpServerResponse write(InputStream in, int length, String contentType) {
|
||||
setContentType(contentType);
|
||||
return write(in, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出数据到客户端
|
||||
*
|
||||
* @param in 数据流
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse write(InputStream in) {
|
||||
return write(in, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写出数据到客户端
|
||||
*
|
||||
* @param in 数据流
|
||||
* @param length 指定响应内容长度,默认0表示不定长度,会输出Transfer-encoding: chunked
|
||||
* @return this
|
||||
*/
|
||||
public HttpServerResponse write(InputStream in, int length) {
|
||||
if (!isSendCode) {
|
||||
sendOk(Math.max(0, length));
|
||||
}
|
||||
OutputStream out = null;
|
||||
try {
|
||||
out = this.httpExchange.getResponseBody();
|
||||
IoUtil.copy(in, out);
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
IoUtil.close(in);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回文件给客户端(文件下载)
|
||||
*
|
||||
* @param file 写出的文件对象
|
||||
* @return this
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public HttpServerResponse write(File file) {
|
||||
return write(file, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回文件给客户端(文件下载)
|
||||
*
|
||||
* @param file 写出的文件对象
|
||||
* @param fileName 文件名
|
||||
* @return this
|
||||
* @since 5.5.8
|
||||
*/
|
||||
public HttpServerResponse write(File file, String fileName) {
|
||||
final long fileSize = file.length();
|
||||
if (fileSize > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("File size is too bigger than " + Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(fileName)) {
|
||||
fileName = file.getName();
|
||||
}
|
||||
final String contentType = ObjectUtil.defaultIfNull(HttpUtil.getMimeType(fileName), "application/octet-stream");
|
||||
BufferedInputStream in = null;
|
||||
try {
|
||||
in = FileUtil.getInputStream(file);
|
||||
write(in, (int) fileSize, contentType, fileName);
|
||||
} finally {
|
||||
IoUtil.close(in);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回文件数据给客户端(文件下载)
|
||||
*
|
||||
* @param in 需要返回客户端的内容
|
||||
* @param contentType 返回的类型
|
||||
* @param fileName 文件名
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public void write(InputStream in, String contentType, String fileName) {
|
||||
write(in, 0, contentType, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回文件数据给客户端(文件下载)
|
||||
*
|
||||
* @param in 需要返回客户端的内容
|
||||
* @param length 长度
|
||||
* @param contentType 返回的类型
|
||||
* @param fileName 文件名
|
||||
* @return this
|
||||
* @since 5.2.7
|
||||
*/
|
||||
public HttpServerResponse write(InputStream in, int length, String contentType, String fileName) {
|
||||
final Charset charset = ObjectUtil.defaultIfNull(this.charset, DEFAULT_CHARSET);
|
||||
|
||||
if (!contentType.startsWith("text/")) {
|
||||
// 非文本类型数据直接走下载
|
||||
setHeader(Header.CONTENT_DISPOSITION, StrUtil.format("attachment;filename={}", URLUtil.encode(fileName, charset)));
|
||||
}
|
||||
return write(in, length, contentType);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.server;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
|
||||
import aiyh.utils.tool.cn.hutool.core.lang.Console;
|
||||
import aiyh.utils.tool.cn.hutool.core.thread.GlobalThreadPool;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.action.Action;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.action.RootAction;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.filter.HttpFilter;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.filter.SimpleFilter;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.handler.ActionHandler;
|
||||
import com.sun.net.httpserver.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* 简易Http服务器,基于{@link HttpServer}
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.2.5
|
||||
*/
|
||||
public class SimpleServer {
|
||||
|
||||
private final HttpServer server;
|
||||
private final List<Filter> filters;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param port 监听端口
|
||||
*/
|
||||
public SimpleServer(int port) {
|
||||
this(new InetSocketAddress(port));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param hostname 监听地址
|
||||
* @param port 监听端口
|
||||
*/
|
||||
public SimpleServer(String hostname, int port) {
|
||||
this(new InetSocketAddress(hostname, port));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param address 监听地址
|
||||
*/
|
||||
public SimpleServer(InetSocketAddress address) {
|
||||
this(address, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param address 监听地址
|
||||
* @param configurator https配置信息,用于使用自定义SSL(TLS)证书等
|
||||
*/
|
||||
public SimpleServer(InetSocketAddress address, HttpsConfigurator configurator) {
|
||||
try {
|
||||
if (null != configurator) {
|
||||
final HttpsServer server = HttpsServer.create(address, 0);
|
||||
server.setHttpsConfigurator(configurator);
|
||||
this.server = server;
|
||||
} else {
|
||||
this.server = HttpServer.create(address, 0);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
setExecutor(GlobalThreadPool.getExecutor());
|
||||
filters = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加请求过滤器,此过滤器对所有请求有效<br>
|
||||
* 此方法需在以下方法前之前调用:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #setRoot(File)} </li>
|
||||
* <li>{@link #setRoot(String)} </li>
|
||||
* <li>{@link #createContext(String, HttpHandler)} </li>
|
||||
* <li>{@link #addHandler(String, HttpHandler)}</li>
|
||||
* <li>{@link #addAction(String, Action)} </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param filter {@link Filter} 请求过滤器
|
||||
* @return this
|
||||
* @since 5.5.7
|
||||
*/
|
||||
public SimpleServer addFilter(Filter filter) {
|
||||
this.filters.add(filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加请求过滤器,此过滤器对所有请求有效<br>
|
||||
* 此方法需在以下方法前之前调用:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #setRoot(File)} </li>
|
||||
* <li>{@link #setRoot(String)} </li>
|
||||
* <li>{@link #createContext(String, HttpHandler)} </li>
|
||||
* <li>{@link #addHandler(String, HttpHandler)}</li>
|
||||
* <li>{@link #addAction(String, Action)} </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param filter {@link Filter} 请求过滤器
|
||||
* @return this
|
||||
* @since 5.5.7
|
||||
*/
|
||||
public SimpleServer addFilter(HttpFilter filter) {
|
||||
return addFilter(new SimpleFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpExchange httpExchange, Chain chain) throws IOException {
|
||||
filter.doFilter(new HttpServerRequest(httpExchange), new HttpServerResponse(httpExchange), chain);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加请求处理规则
|
||||
*
|
||||
* @param path 路径,例如:/a/b 或者 a/b
|
||||
* @param handler 处理器,包括请求和响应处理
|
||||
* @return this
|
||||
* @see #createContext(String, HttpHandler)
|
||||
*/
|
||||
public SimpleServer addHandler(String path, HttpHandler handler) {
|
||||
createContext(path, handler);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建请求映射上下文,创建后,用户访问指定路径可使用{@link HttpHandler} 中的规则进行处理
|
||||
*
|
||||
* @param path 路径,例如:/a/b 或者 a/b
|
||||
* @param handler 处理器,包括请求和响应处理
|
||||
* @return {@link HttpContext}
|
||||
* @since 5.5.7
|
||||
*/
|
||||
public HttpContext createContext(String path, HttpHandler handler) {
|
||||
// 非/开头的路径会报错
|
||||
path = StrUtil.addPrefixIfNot(path, StrUtil.SLASH);
|
||||
final HttpContext context = this.server.createContext(path, handler);
|
||||
// 增加整体过滤器
|
||||
context.getFilters().addAll(this.filters);
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置根目录,默认的页面从root目录中读取解析返回
|
||||
*
|
||||
* @param root 路径
|
||||
* @return this
|
||||
*/
|
||||
public SimpleServer setRoot(String root) {
|
||||
return setRoot(new File(root));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置根目录,默认的页面从root目录中读取解析返回
|
||||
*
|
||||
* @param root 路径
|
||||
* @return this
|
||||
*/
|
||||
public SimpleServer setRoot(File root) {
|
||||
return addAction("/", new RootAction(root));
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加请求处理规则
|
||||
*
|
||||
* @param path 路径
|
||||
* @param action 处理器
|
||||
* @return this
|
||||
*/
|
||||
public SimpleServer addAction(String path, Action action) {
|
||||
return addHandler(path, new ActionHandler(action));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置自定义线程池
|
||||
*
|
||||
* @param executor {@link Executor}
|
||||
* @return this
|
||||
*/
|
||||
public SimpleServer setExecutor(Executor executor) {
|
||||
this.server.setExecutor(executor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得原始HttpServer对象
|
||||
*
|
||||
* @return {@link HttpServer}
|
||||
*/
|
||||
public HttpServer getRawServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务器地址信息
|
||||
*
|
||||
* @return {@link InetSocketAddress}
|
||||
*/
|
||||
public InetSocketAddress getAddress() {
|
||||
return this.server.getAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动Http服务器,启动后会阻塞当前线程
|
||||
*/
|
||||
public void start() {
|
||||
final InetSocketAddress address = getAddress();
|
||||
Console.log("Hutool Simple Http Server listen on 【{}:{}】", address.getHostName(), address.getPort());
|
||||
this.server.start();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.server.action;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.http.server.HttpServerRequest;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.HttpServerResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 请求处理接口<br>
|
||||
* 当用户请求某个Path,则调用相应Action的doAction方法
|
||||
*
|
||||
* @author Looly
|
||||
* @since 5.2.6
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Action {
|
||||
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @param response 响应对象
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
void doAction(HttpServerRequest request, HttpServerResponse response) throws IOException;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.server.action;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.FileUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.HttpServerRequest;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.HttpServerResponse;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 默认的处理器,通过解析用户传入的path,找到网页根目录下对应文件后返回
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public class RootAction implements Action {
|
||||
|
||||
public static final String DEFAULT_INDEX_FILE_NAME = "index.html";
|
||||
|
||||
private final File rootDir;
|
||||
private final List<String> indexFileNames;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param rootDir 网页根目录
|
||||
*/
|
||||
public RootAction(String rootDir) {
|
||||
this(new File(rootDir));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param rootDir 网页根目录
|
||||
*/
|
||||
public RootAction(File rootDir) {
|
||||
this(rootDir, DEFAULT_INDEX_FILE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param rootDir 网页根目录
|
||||
* @param indexFileNames 主页文件名列表
|
||||
*/
|
||||
public RootAction(String rootDir, String... indexFileNames) {
|
||||
this(new File(rootDir), indexFileNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param rootDir 网页根目录
|
||||
* @param indexFileNames 主页文件名列表
|
||||
* @since 5.4.0
|
||||
*/
|
||||
public RootAction(File rootDir, String... indexFileNames) {
|
||||
this.rootDir = rootDir;
|
||||
this.indexFileNames = CollUtil.toList(indexFileNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(HttpServerRequest request, HttpServerResponse response) {
|
||||
final String path = request.getPath();
|
||||
|
||||
File file = FileUtil.file(rootDir, path);
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
for (String indexFileName : indexFileNames) {
|
||||
// 默认读取主页
|
||||
file = FileUtil.file(file, indexFileName);
|
||||
if (file.exists() && file.isFile()) {
|
||||
response.write(file);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final String name = request.getParam("name");
|
||||
response.write(file, name);
|
||||
}
|
||||
}
|
||||
|
||||
response.send404("404 Not Found !");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* {@link com.sun.net.httpserver.HttpServer} 封装
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http.server.action;
|
|
@ -0,0 +1,27 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.server.filter;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.http.server.HttpServerRequest;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.HttpServerResponse;
|
||||
import com.sun.net.httpserver.Filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 过滤器接口,用于简化{@link Filter} 使用
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.5.7
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface HttpFilter {
|
||||
|
||||
/**
|
||||
* 执行过滤
|
||||
*
|
||||
* @param req {@link aiyh.utils.tool.cn.hutool.http.server.HttpServerRequest} 请求对象,用于获取请求内容
|
||||
* @param res {@link aiyh.utils.tool.cn.hutool.http.server.HttpServerResponse} 响应对象,用于写出内容
|
||||
* @param chain {@link Filter.Chain}
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
void doFilter(HttpServerRequest req, HttpServerResponse res, Filter.Chain chain) throws IOException;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.server.filter;
|
||||
|
||||
import com.sun.net.httpserver.Filter;
|
||||
|
||||
/**
|
||||
* 匿名简单过滤器,跳过了描述
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.5.7
|
||||
*/
|
||||
public abstract class SimpleFilter extends Filter {
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Anonymous Filter";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* {@link com.sun.net.httpserver.Filter} 实现包装
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http.server.filter;
|
|
@ -0,0 +1,38 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.server.handler;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.http.server.HttpServerRequest;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.HttpServerResponse;
|
||||
import aiyh.utils.tool.cn.hutool.http.server.action.Action;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Action处理器,用于将HttpHandler转换为Action形式
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public class ActionHandler implements HttpHandler {
|
||||
|
||||
private final Action action;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param action Action
|
||||
*/
|
||||
public ActionHandler(Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange httpExchange) throws IOException {
|
||||
action.doAction(
|
||||
new HttpServerRequest(httpExchange),
|
||||
new HttpServerResponse(httpExchange)
|
||||
);
|
||||
httpExchange.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* {@link com.sun.net.httpserver.HttpHandler} 实现包装
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http.server.handler;
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* Http服务器封装
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http.server;
|
|
@ -0,0 +1,25 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.ssl;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
|
||||
import aiyh.utils.tool.cn.hutool.core.net.SSLProtocols;
|
||||
|
||||
/**
|
||||
* 兼容android低版本SSL连接<br>
|
||||
* 在测试HttpUrlConnection的时候,发现一部分手机无法连接[GithubPage]
|
||||
*
|
||||
* <p>
|
||||
* 最后发现原来是某些SSL协议没有开启
|
||||
*
|
||||
* @author MikaGuraNTK
|
||||
*/
|
||||
public class AndroidSupportSSLFactory extends CustomProtocolsSSLFactory {
|
||||
|
||||
// Android低版本不重置的话某些SSL访问就会失败
|
||||
private static final String[] protocols = {
|
||||
SSLProtocols.SSLv3, SSLProtocols.TLSv1, SSLProtocols.TLSv11, SSLProtocols.TLSv12};
|
||||
|
||||
public AndroidSupportSSLFactory() throws IORuntimeException {
|
||||
super(protocols);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.ssl;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
|
||||
import aiyh.utils.tool.cn.hutool.core.net.SSLUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
|
||||
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* 自定义支持协议类型的SSLSocketFactory
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public class CustomProtocolsSSLFactory extends SSLSocketFactory {
|
||||
|
||||
private final String[] protocols;
|
||||
private final SSLSocketFactory base;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param protocols 支持协议列表
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public CustomProtocolsSSLFactory(String... protocols) throws IORuntimeException {
|
||||
this.protocols = protocols;
|
||||
this.base = SSLUtil.createSSLContext(null).getSocketFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDefaultCipherSuites() {
|
||||
return base.getDefaultCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedCipherSuites() {
|
||||
return base.getSupportedCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
final SSLSocket sslSocket = (SSLSocket) base.createSocket();
|
||||
resetProtocols(sslSocket);
|
||||
return sslSocket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(s, host, port, autoClose);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException {
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(host, port);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(host, port, localHost, localPort);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(host, port);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
||||
final SSLSocket socket = (SSLSocket) base.createSocket(address, port, localAddress, localPort);
|
||||
resetProtocols(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置可用策略
|
||||
*
|
||||
* @param socket SSLSocket
|
||||
*/
|
||||
private void resetProtocols(SSLSocket socket) {
|
||||
if (ArrayUtil.isNotEmpty(this.protocols)) {
|
||||
socket.setEnabledProtocols(this.protocols);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.ssl;
|
||||
|
||||
/**
|
||||
* 默认的SSLSocketFactory
|
||||
*
|
||||
* @author Looly
|
||||
* @since 5.1.2
|
||||
*/
|
||||
public class DefaultSSLFactory extends CustomProtocolsSSLFactory {
|
||||
|
||||
public DefaultSSLFactory() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.ssl;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
/**
|
||||
* 默认的全局SSL配置,当用户未设置相关信息时,使用默认设置,默认设置为单例模式。
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.1.2
|
||||
*/
|
||||
public class DefaultSSLInfo {
|
||||
/**
|
||||
* 默认信任全部的域名校验器
|
||||
*/
|
||||
public static final aiyh.utils.tool.cn.hutool.http.ssl.TrustAnyHostnameVerifier TRUST_ANY_HOSTNAME_VERIFIER;
|
||||
/**
|
||||
* 默认的SSLSocketFactory,区分安卓
|
||||
*/
|
||||
public static final SSLSocketFactory DEFAULT_SSF;
|
||||
|
||||
static {
|
||||
TRUST_ANY_HOSTNAME_VERIFIER = new TrustAnyHostnameVerifier();
|
||||
if (StrUtil.equalsIgnoreCase("dalvik", System.getProperty("java.vm.name"))) {
|
||||
// 兼容android低版本SSL连接
|
||||
DEFAULT_SSF = new AndroidSupportSSLFactory();
|
||||
} else {
|
||||
DEFAULT_SSF = new DefaultSSLFactory();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.ssl;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.net.SSLContextBuilder;
|
||||
import aiyh.utils.tool.cn.hutool.core.net.SSLProtocols;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* SSLSocketFactory构建器
|
||||
*
|
||||
* @author Looly
|
||||
* @see SSLContextBuilder
|
||||
* @deprecated 请使用 {@link SSLContextBuilder}
|
||||
*/
|
||||
@Deprecated
|
||||
public class SSLSocketFactoryBuilder implements SSLProtocols {
|
||||
|
||||
SSLContextBuilder sslContextBuilder;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
public SSLSocketFactoryBuilder() {
|
||||
this.sslContextBuilder = SSLContextBuilder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 SSLSocketFactoryBuilder
|
||||
*
|
||||
* @return SSLSocketFactoryBuilder
|
||||
*/
|
||||
public static SSLSocketFactoryBuilder create() {
|
||||
return new SSLSocketFactoryBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置协议
|
||||
*
|
||||
* @param protocol 协议
|
||||
* @return 自身
|
||||
*/
|
||||
public SSLSocketFactoryBuilder setProtocol(String protocol) {
|
||||
this.sslContextBuilder.setProtocol(protocol);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置信任信息
|
||||
*
|
||||
* @param trustManagers TrustManager列表
|
||||
* @return 自身
|
||||
*/
|
||||
public SSLSocketFactoryBuilder setTrustManagers(TrustManager... trustManagers) {
|
||||
this.sslContextBuilder.setTrustManagers(trustManagers);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 JSSE key managers
|
||||
*
|
||||
* @param keyManagers JSSE key managers
|
||||
* @return 自身
|
||||
*/
|
||||
public SSLSocketFactoryBuilder setKeyManagers(KeyManager... keyManagers) {
|
||||
this.sslContextBuilder.setKeyManagers(keyManagers);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 SecureRandom
|
||||
*
|
||||
* @param secureRandom SecureRandom
|
||||
* @return 自己
|
||||
*/
|
||||
public SSLSocketFactoryBuilder setSecureRandom(SecureRandom secureRandom) {
|
||||
this.sslContextBuilder.setSecureRandom(secureRandom);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建SSLSocketFactory
|
||||
*
|
||||
* @return SSLSocketFactory
|
||||
* @throws NoSuchAlgorithmException 无此算法
|
||||
* @throws KeyManagementException Key管理异常
|
||||
*/
|
||||
public SSLSocketFactory build() throws NoSuchAlgorithmException, KeyManagementException {
|
||||
return this.sslContextBuilder.buildChecked().getSocketFactory();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.ssl;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
/**
|
||||
* https 域名校验
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class TrustAnyHostnameVerifier implements HostnameVerifier {
|
||||
|
||||
@Override
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;// 直接返回true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* SSL封装
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http.ssl;
|
|
@ -0,0 +1,140 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.useragent;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ReUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 浏览器对象
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public class Browser extends UserAgentInfo {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 未知
|
||||
*/
|
||||
public static final Browser Unknown = new Browser(NameUnknown, null, null);
|
||||
/**
|
||||
* 其它版本
|
||||
*/
|
||||
public static final String Other_Version = "[\\/ ]([\\d\\w\\.\\-]+)";
|
||||
|
||||
/**
|
||||
* 支持的浏览器类型
|
||||
*/
|
||||
public static final List<Browser> browers = CollUtil.newArrayList(
|
||||
// 部分特殊浏览器是基于安卓、Iphone等的,需要优先判断
|
||||
// 企业微信 企业微信使用微信浏览器内核,会包含 MicroMessenger 所以要放在前面
|
||||
new Browser("wxwork", "wxwork", "wxwork\\/([\\d\\w\\.\\-]+)"),
|
||||
// 微信
|
||||
new Browser("MicroMessenger", "MicroMessenger", Other_Version),
|
||||
// 微信小程序
|
||||
new Browser("miniProgram", "miniProgram", Other_Version),
|
||||
// QQ浏览器
|
||||
new Browser("QQBrowser", "MQQBrowser", "MQQBrowser\\/([\\d\\w\\.\\-]+)"),
|
||||
// 钉钉PC端浏览器
|
||||
new Browser("DingTalk-win", "dingtalk-win", "DingTalk\\(([\\d\\w\\.\\-]+)\\)"),
|
||||
// 钉钉内置浏览器
|
||||
new Browser("DingTalk", "DingTalk", "AliApp\\(DingTalk\\/([\\d\\w\\.\\-]+)\\)"),
|
||||
// 支付宝内置浏览器
|
||||
new Browser("Alipay", "AlipayClient", "AliApp\\(AP\\/([\\d\\w\\.\\-]+)\\)"),
|
||||
// 淘宝内置浏览器
|
||||
new Browser("Taobao", "taobao", "AliApp\\(TB\\/([\\d\\w\\.\\-]+)\\)"),
|
||||
// UC浏览器
|
||||
new Browser("UCBrowser", "UC?Browser", "UC?Browser\\/([\\d\\w\\.\\-]+)"),
|
||||
// XiaoMi 浏览器
|
||||
new Browser("MiuiBrowser", "MiuiBrowser|mibrowser", "MiuiBrowser\\/([\\d\\w\\.\\-]+)"),
|
||||
// 夸克浏览器
|
||||
new Browser("Quark", "Quark", Other_Version),
|
||||
// 联想浏览器
|
||||
new Browser("Lenovo", "SLBrowser", "SLBrowser/([\\d\\w\\.\\-]+)"),
|
||||
new Browser("MSEdge", "Edge|Edg", "(?:edge|Edg|EdgA)\\/([\\d\\w\\.\\-]+)"),
|
||||
new Browser("Chrome", "chrome", Other_Version),
|
||||
new Browser("Firefox", "firefox", Other_Version),
|
||||
new Browser("IEMobile", "iemobile", Other_Version),
|
||||
new Browser("Android Browser", "android", "version\\/([\\d\\w\\.\\-]+)"),
|
||||
new Browser("Safari", "safari", "version\\/([\\d\\w\\.\\-]+)"),
|
||||
new Browser("Opera", "opera", Other_Version),
|
||||
new Browser("Konqueror", "konqueror", Other_Version),
|
||||
new Browser("PS3", "playstation 3", "([\\d\\w\\.\\-]+)\\)\\s*$"),
|
||||
new Browser("PSP", "playstation portable", "([\\d\\w\\.\\-]+)\\)?\\s*$"),
|
||||
new Browser("Lotus", "lotus.notes", "Lotus-Notes\\/([\\w.]+)"),
|
||||
new Browser("Thunderbird", "thunderbird", Other_Version),
|
||||
new Browser("Netscape", "netscape", Other_Version),
|
||||
new Browser("Seamonkey", "seamonkey", Other_Version),
|
||||
new Browser("Outlook", "microsoft.outlook", Other_Version),
|
||||
new Browser("Evolution", "evolution", Other_Version),
|
||||
new Browser("MSIE", "msie", "msie ([\\d\\w\\.\\-]+)"),
|
||||
new Browser("MSIE11", "rv:11", "rv:([\\d\\w\\.\\-]+)"),
|
||||
new Browser("Gabble", "Gabble", Other_Version),
|
||||
new Browser("Yammer Desktop", "AdobeAir", "([\\d\\w\\.\\-]+)\\/Yammer"),
|
||||
new Browser("Yammer Mobile", "Yammer[\\s]+([\\d\\w\\.\\-]+)", "Yammer[\\s]+([\\d\\w\\.\\-]+)"),
|
||||
new Browser("Apache HTTP Client", "Apache\\\\-HttpClient", "Apache\\-HttpClient\\/([\\d\\w\\.\\-]+)"),
|
||||
new Browser("BlackBerry", "BlackBerry", "BlackBerry[\\d]+\\/([\\d\\w\\.\\-]+)")
|
||||
);
|
||||
|
||||
/**
|
||||
* 添加自定义的浏览器类型
|
||||
*
|
||||
* @param name 浏览器名称
|
||||
* @param regex 关键字或表达式
|
||||
* @param versionRegex 匹配版本的正则
|
||||
* @since 5.7.4
|
||||
*/
|
||||
synchronized public static void addCustomBrowser(String name, String regex, String versionRegex) {
|
||||
browers.add(new Browser(name, regex, versionRegex));
|
||||
}
|
||||
|
||||
private Pattern versionPattern;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param name 浏览器名称
|
||||
* @param regex 关键字或表达式
|
||||
* @param versionRegex 匹配版本的正则
|
||||
*/
|
||||
public Browser(String name, String regex, String versionRegex) {
|
||||
super(name, regex);
|
||||
if (Other_Version.equals(versionRegex)) {
|
||||
versionRegex = name + versionRegex;
|
||||
}
|
||||
if (null != versionRegex) {
|
||||
this.versionPattern = Pattern.compile(versionRegex, Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器版本
|
||||
*
|
||||
* @param userAgentString User-Agent字符串
|
||||
* @return 版本
|
||||
*/
|
||||
public String getVersion(String userAgentString) {
|
||||
if (isUnknown()) {
|
||||
return null;
|
||||
}
|
||||
return ReUtil.getGroup1(this.versionPattern, userAgentString);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否移动浏览器
|
||||
*
|
||||
* @return 是否移动浏览器
|
||||
*/
|
||||
public boolean isMobile() {
|
||||
final String name = this.getName();
|
||||
return "PSP".equals(name) ||
|
||||
"Yammer Mobile".equals(name) ||
|
||||
"Android Browser".equals(name) ||
|
||||
"IEMobile".equals(name) ||
|
||||
"MicroMessenger".equals(name) ||
|
||||
"miniProgram".equals(name) ||
|
||||
"DingTalk".equals(name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.useragent;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ReUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 引擎对象
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public class Engine extends UserAgentInfo {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 未知 */
|
||||
public static final Engine Unknown = new Engine(NameUnknown, null);
|
||||
|
||||
/**
|
||||
* 支持的引擎类型
|
||||
*/
|
||||
public static final List<Engine> engines = CollUtil.newArrayList(
|
||||
new Engine("Trident", "trident"),
|
||||
new Engine("Webkit", "webkit"),
|
||||
new Engine("Chrome", "chrome"),
|
||||
new Engine("Opera", "opera"),
|
||||
new Engine("Presto", "presto"),
|
||||
new Engine("Gecko", "gecko"),
|
||||
new Engine("KHTML", "khtml"),
|
||||
new Engine("Konqueror", "konqueror"),
|
||||
new Engine("MIDP", "MIDP")
|
||||
);
|
||||
|
||||
private final Pattern versionPattern;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param name 引擎名称
|
||||
* @param regex 关键字或表达式
|
||||
*/
|
||||
public Engine(String name, String regex) {
|
||||
super(name, regex);
|
||||
this.versionPattern = Pattern.compile(name + "[/\\- ]([\\d\\w.\\-]+)", Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取引擎版本
|
||||
*
|
||||
* @param userAgentString User-Agent字符串
|
||||
* @return 版本
|
||||
* @since 5.7.4
|
||||
*/
|
||||
public String getVersion(String userAgentString) {
|
||||
if (isUnknown()) {
|
||||
return null;
|
||||
}
|
||||
return ReUtil.getGroup1(this.versionPattern, userAgentString);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.useragent;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ReUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 系统对象
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public class OS extends UserAgentInfo {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 未知
|
||||
*/
|
||||
public static final OS Unknown = new OS(NameUnknown, null);
|
||||
|
||||
/**
|
||||
* 支持的引擎类型
|
||||
*/
|
||||
public static final List<OS> oses = CollUtil.newArrayList(//
|
||||
new OS("Windows 10 or Windows Server 2016", "windows nt 10\\.0", "windows nt (10\\.0)"),//
|
||||
new OS("Windows 8.1 or Windows Server 2012R2", "windows nt 6\\.3", "windows nt (6\\.3)"),//
|
||||
new OS("Windows 8 or Windows Server 2012", "windows nt 6\\.2", "windows nt (6\\.2)"),//
|
||||
new OS("Windows Vista", "windows nt 6\\.0", "windows nt (6\\.0)"), //
|
||||
new OS("Windows 7 or Windows Server 2008R2", "windows nt 6\\.1", "windows nt (6\\.1)"), //
|
||||
new OS("Windows 2003", "windows nt 5\\.2", "windows nt (5\\.2)"), //
|
||||
new OS("Windows XP", "windows nt 5\\.1", "windows nt (5\\.1)"), //
|
||||
new OS("Windows 2000", "windows nt 5\\.0", "windows nt (5\\.0)"), //
|
||||
new OS("Windows Phone", "windows (ce|phone|mobile)( os)?", "windows (?:ce|phone|mobile) (\\d+([._]\\d+)*)"), //
|
||||
new OS("Windows", "windows"), //
|
||||
new OS("OSX", "os x (\\d+)[._](\\d+)", "os x (\\d+([._]\\d+)*)"), //
|
||||
new OS("Android", "Android", "Android (\\d+([._]\\d+)*)"),//
|
||||
new OS("Android", "XiaoMi|MI\\s+", "\\(X(\\d+([._]\\d+)*)"),//
|
||||
new OS("Linux", "linux"), //
|
||||
new OS("Wii", "wii", "wii libnup/(\\d+([._]\\d+)*)"), //
|
||||
new OS("PS3", "playstation 3", "playstation 3; (\\d+([._]\\d+)*)"), //
|
||||
new OS("PSP", "playstation portable", "Portable\\); (\\d+([._]\\d+)*)"), //
|
||||
new OS("iPad", "\\(iPad.*os (\\d+)[._](\\d+)", "\\(iPad.*os (\\d+([._]\\d+)*)"), //
|
||||
new OS("iPhone", "\\(iPhone.*os (\\d+)[._](\\d+)", "\\(iPhone.*os (\\d+([._]\\d+)*)"), //
|
||||
new OS("YPod", "iPod touch[\\s\\;]+iPhone.*os (\\d+)[._](\\d+)", "iPod touch[\\s\\;]+iPhone.*os (\\d+([._]\\d+)*)"), //
|
||||
new OS("YPad", "iPad[\\s\\;]+iPhone.*os (\\d+)[._](\\d+)", "iPad[\\s\\;]+iPhone.*os (\\d+([._]\\d+)*)"), //
|
||||
new OS("YPhone", "iPhone[\\s\\;]+iPhone.*os (\\d+)[._](\\d+)", "iPhone[\\s\\;]+iPhone.*os (\\d+([._]\\d+)*)"), //
|
||||
new OS("Symbian", "symbian(os)?"), //
|
||||
new OS("Darwin", "Darwin\\/([\\d\\w\\.\\-]+)", "Darwin\\/([\\d\\w\\.\\-]+)"), //
|
||||
new OS("Adobe Air", "AdobeAir\\/([\\d\\w\\.\\-]+)", "AdobeAir\\/([\\d\\w\\.\\-]+)"), //
|
||||
new OS("Java", "Java[\\s]+([\\d\\w\\.\\-]+)", "Java[\\s]+([\\d\\w\\.\\-]+)")//
|
||||
);
|
||||
|
||||
/**
|
||||
* 添加自定义的系统类型
|
||||
*
|
||||
* @param name 浏览器名称
|
||||
* @param regex 关键字或表达式
|
||||
* @param versionRegex 匹配版本的正则
|
||||
* @since 5.7.4
|
||||
*/
|
||||
synchronized public static void addCustomOs(String name, String regex, String versionRegex) {
|
||||
oses.add(new OS(name, regex, versionRegex));
|
||||
}
|
||||
|
||||
private Pattern versionPattern;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param name 系统名称
|
||||
* @param regex 关键字或表达式
|
||||
*/
|
||||
public OS(String name, String regex) {
|
||||
this(name, regex, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param name 系统名称
|
||||
* @param regex 关键字或表达式
|
||||
* @param versionRegex 版本正则表达式
|
||||
* @since 5.7.4
|
||||
*/
|
||||
public OS(String name, String regex, String versionRegex) {
|
||||
super(name, regex);
|
||||
if (null != versionRegex) {
|
||||
this.versionPattern = Pattern.compile(versionRegex, Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器版本
|
||||
*
|
||||
* @param userAgentString User-Agent字符串
|
||||
* @return 版本
|
||||
*/
|
||||
public String getVersion(String userAgentString) {
|
||||
if (isUnknown() || null == this.versionPattern) {
|
||||
// 无版本信息
|
||||
return null;
|
||||
}
|
||||
return ReUtil.getGroup1(this.versionPattern, userAgentString);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.useragent;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 平台对象
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public class Platform extends UserAgentInfo {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 未知
|
||||
*/
|
||||
public static final Platform Unknown = new Platform(NameUnknown, null);
|
||||
|
||||
/**
|
||||
* Iphone
|
||||
*/
|
||||
public static final Platform IPHONE = new Platform("iPhone", "iphone");
|
||||
/**
|
||||
* ipod
|
||||
*/
|
||||
public static final Platform IPOD = new Platform("iPod", "ipod");
|
||||
/**
|
||||
* ipad
|
||||
*/
|
||||
public static final Platform IPAD = new Platform("iPad", "ipad");
|
||||
|
||||
/**
|
||||
* android
|
||||
*/
|
||||
public static final Platform ANDROID = new Platform("Android", "android");
|
||||
/**
|
||||
* android
|
||||
*/
|
||||
public static final Platform GOOGLE_TV = new Platform("GoogleTV", "googletv");
|
||||
|
||||
/**
|
||||
* Windows Phone
|
||||
*/
|
||||
public static final Platform WINDOWS_PHONE = new Platform("Windows Phone", "windows (ce|phone|mobile)( os)?");
|
||||
|
||||
/**
|
||||
* 支持的移动平台类型
|
||||
*/
|
||||
public static final List<Platform> mobilePlatforms = CollUtil.newArrayList(//
|
||||
WINDOWS_PHONE, //
|
||||
IPAD, //
|
||||
IPOD, //
|
||||
IPHONE, //
|
||||
new Platform("Android", "XiaoMi|MI\\s+"), //
|
||||
ANDROID, //
|
||||
GOOGLE_TV, //
|
||||
new Platform("htcFlyer", "htc_flyer"), //
|
||||
new Platform("Symbian", "symbian(os)?"), //
|
||||
new Platform("Blackberry", "blackberry") //
|
||||
);
|
||||
|
||||
/**
|
||||
* 支持的桌面平台类型
|
||||
*/
|
||||
public static final List<Platform> desktopPlatforms = CollUtil.newArrayList(//
|
||||
new Platform("Windows", "windows"), //
|
||||
new Platform("Mac", "(macintosh|darwin)"), //
|
||||
new Platform("Linux", "linux"), //
|
||||
new Platform("Wii", "wii"), //
|
||||
new Platform("Playstation", "playstation"), //
|
||||
new Platform("Java", "java") //
|
||||
);
|
||||
|
||||
/**
|
||||
* 支持的平台类型
|
||||
*/
|
||||
public static final List<Platform> platforms;
|
||||
|
||||
static {
|
||||
platforms = new ArrayList<>(13);
|
||||
platforms.addAll(mobilePlatforms);
|
||||
platforms.addAll(desktopPlatforms);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param name 平台名称
|
||||
* @param regex 关键字或表达式
|
||||
*/
|
||||
public Platform(String name, String regex) {
|
||||
super(name, regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为移动平台
|
||||
*
|
||||
* @return 是否为移动平台
|
||||
*/
|
||||
public boolean isMobile() {
|
||||
return mobilePlatforms.contains(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为Iphone或者iPod设备
|
||||
*
|
||||
* @return 是否为Iphone或者iPod设备
|
||||
* @since 5.2.3
|
||||
*/
|
||||
public boolean isIPhoneOrIPod() {
|
||||
return this.equals(IPHONE) || this.equals(IPOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为Iphone或者iPod设备
|
||||
*
|
||||
* @return 是否为Iphone或者iPod设备
|
||||
* @since 5.2.3
|
||||
*/
|
||||
public boolean isIPad() {
|
||||
return this.equals(IPAD);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为IOS平台,包括IPhone、IPod、IPad
|
||||
*
|
||||
* @return 是否为IOS平台,包括IPhone、IPod、IPad
|
||||
* @since 5.2.3
|
||||
*/
|
||||
public boolean isIos() {
|
||||
return isIPhoneOrIPod() || isIPad();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为Android平台,包括Android和Google TV
|
||||
*
|
||||
* @return 是否为Android平台,包括Android和Google TV
|
||||
* @since 5.2.3
|
||||
*/
|
||||
public boolean isAndroid() {
|
||||
return this.equals(ANDROID) || this.equals(GOOGLE_TV);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.useragent;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* User-Agent信息对象
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public class UserAgent implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 是否为移动平台
|
||||
*/
|
||||
private boolean mobile;
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private aiyh.utils.tool.cn.hutool.http.useragent.Browser browser;
|
||||
/**
|
||||
* 浏览器版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 平台类型
|
||||
*/
|
||||
private aiyh.utils.tool.cn.hutool.http.useragent.Platform platform;
|
||||
|
||||
/**
|
||||
* 系统类型
|
||||
*/
|
||||
private aiyh.utils.tool.cn.hutool.http.useragent.OS os;
|
||||
/**
|
||||
* 系统版本
|
||||
*/
|
||||
private String osVersion;
|
||||
|
||||
/**
|
||||
* 引擎类型
|
||||
*/
|
||||
private aiyh.utils.tool.cn.hutool.http.useragent.Engine engine;
|
||||
/**
|
||||
* 引擎版本
|
||||
*/
|
||||
private String engineVersion;
|
||||
|
||||
/**
|
||||
* 是否为移动平台
|
||||
*
|
||||
* @return 是否为移动平台
|
||||
*/
|
||||
public boolean isMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否为移动平台
|
||||
*
|
||||
* @param mobile 是否为移动平台
|
||||
*/
|
||||
public void setMobile(boolean mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器类型
|
||||
*
|
||||
* @return 浏览器类型
|
||||
*/
|
||||
public aiyh.utils.tool.cn.hutool.http.useragent.Browser getBrowser() {
|
||||
return browser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置浏览器类型
|
||||
*
|
||||
* @param browser 浏览器类型
|
||||
*/
|
||||
public void setBrowser(Browser browser) {
|
||||
this.browser = browser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平台类型
|
||||
*
|
||||
* @return 平台类型
|
||||
*/
|
||||
public aiyh.utils.tool.cn.hutool.http.useragent.Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置平台类型
|
||||
*
|
||||
* @param platform 平台类型
|
||||
*/
|
||||
public void setPlatform(Platform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统类型
|
||||
*
|
||||
* @return 系统类型
|
||||
*/
|
||||
public aiyh.utils.tool.cn.hutool.http.useragent.OS getOs() {
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统类型
|
||||
*
|
||||
* @param os 系统类型
|
||||
*/
|
||||
public void setOs(OS os) {
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统版本
|
||||
*
|
||||
* @return 系统版本
|
||||
* @since 5.7.4
|
||||
*/
|
||||
public String getOsVersion() {
|
||||
return this.osVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统版本
|
||||
*
|
||||
* @param osVersion 系统版本
|
||||
* @since 5.7.4
|
||||
*/
|
||||
public void setOsVersion(String osVersion) {
|
||||
this.osVersion = osVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取引擎类型
|
||||
*
|
||||
* @return 引擎类型
|
||||
*/
|
||||
public aiyh.utils.tool.cn.hutool.http.useragent.Engine getEngine() {
|
||||
return engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置引擎类型
|
||||
*
|
||||
* @param engine 引擎类型
|
||||
*/
|
||||
public void setEngine(Engine engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器版本
|
||||
*
|
||||
* @return 浏览器版本
|
||||
*/
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置浏览器版本
|
||||
*
|
||||
* @param version 浏览器版本
|
||||
*/
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取引擎版本
|
||||
*
|
||||
* @return 引擎版本
|
||||
*/
|
||||
public String getEngineVersion() {
|
||||
return engineVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置引擎版本
|
||||
*
|
||||
* @param engineVersion 引擎版本
|
||||
*/
|
||||
public void setEngineVersion(String engineVersion) {
|
||||
this.engineVersion = engineVersion;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.useragent;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ReUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* User-agent信息
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public class UserAgentInfo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 未知类型
|
||||
*/
|
||||
public static final String NameUnknown = "Unknown";
|
||||
|
||||
/** 信息名称 */
|
||||
private final String name;
|
||||
/** 信息匹配模式 */
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param name 名字
|
||||
* @param regex 表达式
|
||||
*/
|
||||
public UserAgentInfo(String name, String regex) {
|
||||
this(name, (null == regex) ? null : Pattern.compile(regex, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param name 名字
|
||||
* @param pattern 匹配模式
|
||||
*/
|
||||
public UserAgentInfo(String name, Pattern pattern) {
|
||||
this.name = name;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取信息名称
|
||||
*
|
||||
* @return 信息名称
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取匹配模式
|
||||
*
|
||||
* @return 匹配模式
|
||||
*/
|
||||
public Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定内容中是否包含匹配此信息的内容
|
||||
*
|
||||
* @param content User-Agent字符串
|
||||
* @return 是否包含匹配此信息的内容
|
||||
*/
|
||||
public boolean isMatch(String content) {
|
||||
return ReUtil.contains(this.pattern, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为Unknown
|
||||
*
|
||||
* @return 是否为Unknown
|
||||
*/
|
||||
public boolean isUnknown() {
|
||||
return NameUnknown.equals(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final UserAgentInfo other = (UserAgentInfo) obj;
|
||||
if (name == null) {
|
||||
return other.name == null;
|
||||
} else return name.equals(other.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.useragent;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* User-Agent解析器
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public class UserAgentParser {
|
||||
|
||||
/**
|
||||
* 解析User-Agent
|
||||
*
|
||||
* @param userAgentString User-Agent字符串
|
||||
* @return {@link UserAgent}
|
||||
*/
|
||||
public static UserAgent parse(String userAgentString) {
|
||||
if (StrUtil.isBlank(userAgentString)) {
|
||||
return null;
|
||||
}
|
||||
final UserAgent userAgent = new UserAgent();
|
||||
|
||||
// 浏览器
|
||||
final aiyh.utils.tool.cn.hutool.http.useragent.Browser browser = parseBrowser(userAgentString);
|
||||
userAgent.setBrowser(browser);
|
||||
userAgent.setVersion(browser.getVersion(userAgentString));
|
||||
|
||||
// 浏览器引擎
|
||||
final aiyh.utils.tool.cn.hutool.http.useragent.Engine engine = parseEngine(userAgentString);
|
||||
userAgent.setEngine(engine);
|
||||
userAgent.setEngineVersion(engine.getVersion(userAgentString));
|
||||
|
||||
// 操作系统
|
||||
final aiyh.utils.tool.cn.hutool.http.useragent.OS os = parseOS(userAgentString);
|
||||
userAgent.setOs(os);
|
||||
userAgent.setOsVersion(os.getVersion(userAgentString));
|
||||
|
||||
// 平台
|
||||
final aiyh.utils.tool.cn.hutool.http.useragent.Platform platform = parsePlatform(userAgentString);
|
||||
userAgent.setPlatform(platform);
|
||||
userAgent.setMobile(platform.isMobile() || browser.isMobile());
|
||||
|
||||
|
||||
return userAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析浏览器类型
|
||||
*
|
||||
* @param userAgentString User-Agent字符串
|
||||
* @return 浏览器类型
|
||||
*/
|
||||
private static aiyh.utils.tool.cn.hutool.http.useragent.Browser parseBrowser(String userAgentString) {
|
||||
for (aiyh.utils.tool.cn.hutool.http.useragent.Browser browser : aiyh.utils.tool.cn.hutool.http.useragent.Browser.browers) {
|
||||
if (browser.isMatch(userAgentString)) {
|
||||
return browser;
|
||||
}
|
||||
}
|
||||
return Browser.Unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析引擎类型
|
||||
*
|
||||
* @param userAgentString User-Agent字符串
|
||||
* @return 引擎类型
|
||||
*/
|
||||
private static aiyh.utils.tool.cn.hutool.http.useragent.Engine parseEngine(String userAgentString) {
|
||||
for (aiyh.utils.tool.cn.hutool.http.useragent.Engine engine : aiyh.utils.tool.cn.hutool.http.useragent.Engine.engines) {
|
||||
if (engine.isMatch(userAgentString)) {
|
||||
return engine;
|
||||
}
|
||||
}
|
||||
return Engine.Unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析系统类型
|
||||
*
|
||||
* @param userAgentString User-Agent字符串
|
||||
* @return 系统类型
|
||||
*/
|
||||
private static aiyh.utils.tool.cn.hutool.http.useragent.OS parseOS(String userAgentString) {
|
||||
for (aiyh.utils.tool.cn.hutool.http.useragent.OS os : aiyh.utils.tool.cn.hutool.http.useragent.OS.oses) {
|
||||
if (os.isMatch(userAgentString)) {
|
||||
return os;
|
||||
}
|
||||
}
|
||||
return OS.Unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析平台类型
|
||||
*
|
||||
* @param userAgentString User-Agent字符串
|
||||
* @return 平台类型
|
||||
*/
|
||||
private static aiyh.utils.tool.cn.hutool.http.useragent.Platform parsePlatform(String userAgentString) {
|
||||
for (aiyh.utils.tool.cn.hutool.http.useragent.Platform platform : aiyh.utils.tool.cn.hutool.http.useragent.Platform.platforms) {
|
||||
if (platform.isMatch(userAgentString)) {
|
||||
return platform;
|
||||
}
|
||||
}
|
||||
return Platform.Unknown;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.useragent;
|
||||
|
||||
/**
|
||||
* User-Agent工具类
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public class UserAgentUtil {
|
||||
|
||||
/**
|
||||
* 解析User-Agent
|
||||
*
|
||||
* @param userAgentString User-Agent字符串
|
||||
* @return {@link UserAgent}
|
||||
*/
|
||||
public static UserAgent parse(String userAgentString) {
|
||||
return UserAgentParser.parse(userAgentString);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* User-Agent解析
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http.useragent;
|
|
@ -0,0 +1,654 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.webservice;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.map.MapUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.XmlUtil;
|
||||
import aiyh.utils.tool.cn.hutool.http.HttpBase;
|
||||
import aiyh.utils.tool.cn.hutool.http.HttpGlobalConfig;
|
||||
import aiyh.utils.tool.cn.hutool.http.HttpRequest;
|
||||
import aiyh.utils.tool.cn.hutool.http.HttpResponse;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.soap.*;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* SOAP客户端
|
||||
*
|
||||
* <p>
|
||||
* 此对象用于构建一个SOAP消息,并通过HTTP接口发出消息内容。
|
||||
* SOAP消息本质上是一个XML文本,可以通过调用{@link #getMsgStr(boolean)} 方法获取消息体
|
||||
* <p>
|
||||
* 使用方法:
|
||||
*
|
||||
* <pre>
|
||||
* SoapClient client = SoapClient.create(url)
|
||||
* .setMethod(methodName, namespaceURI)
|
||||
* .setCharset(CharsetUtil.CHARSET_GBK)
|
||||
* .setParam(param1, "XXX");
|
||||
*
|
||||
* String response = client.send(true);
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.5.4
|
||||
*/
|
||||
public class SoapClient extends HttpBase<SoapClient> {
|
||||
|
||||
/**
|
||||
* XML消息体的Content-Type
|
||||
* soap1.1 : text/xml
|
||||
* soap1.2 : application/soap+xml
|
||||
* soap1.1与soap1.2区别: https://www.cnblogs.com/qlqwjy/p/7577147.html
|
||||
*/
|
||||
private static final String CONTENT_TYPE_SOAP11_TEXT_XML = "text/xml;charset=";
|
||||
private static final String CONTENT_TYPE_SOAP12_SOAP_XML = "application/soap+xml;charset=";
|
||||
|
||||
/**
|
||||
* 请求的URL地址
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 默认连接超时
|
||||
*/
|
||||
private int connectionTimeout = aiyh.utils.tool.cn.hutool.http.HttpGlobalConfig.getTimeout();
|
||||
/**
|
||||
* 默认读取超时
|
||||
*/
|
||||
private int readTimeout = HttpGlobalConfig.getTimeout();
|
||||
|
||||
/**
|
||||
* 消息工厂,用于创建消息
|
||||
*/
|
||||
private MessageFactory factory;
|
||||
/**
|
||||
* SOAP消息
|
||||
*/
|
||||
private SOAPMessage message;
|
||||
/**
|
||||
* 消息方法节点
|
||||
*/
|
||||
private SOAPBodyElement methodEle;
|
||||
/**
|
||||
* 应用于方法上的命名空间URI
|
||||
*/
|
||||
private final String namespaceURI;
|
||||
/**
|
||||
* Soap协议
|
||||
* soap1.1 : text/xml
|
||||
* soap1.2 : application/soap+xml
|
||||
*/
|
||||
private final SoapProtocol protocol;
|
||||
|
||||
/**
|
||||
* 创建SOAP客户端,默认使用soap1.1版本协议
|
||||
*
|
||||
* @param url WS的URL地址
|
||||
* @return this
|
||||
*/
|
||||
public static SoapClient create(String url) {
|
||||
return new SoapClient(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建SOAP客户端
|
||||
*
|
||||
* @param url WS的URL地址
|
||||
* @param protocol 协议,见{@link SoapProtocol}
|
||||
* @return this
|
||||
*/
|
||||
public static SoapClient create(String url, SoapProtocol protocol) {
|
||||
return new SoapClient(url, protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建SOAP客户端
|
||||
*
|
||||
* @param url WS的URL地址
|
||||
* @param protocol 协议,见{@link SoapProtocol}
|
||||
* @param namespaceURI 方法上的命名空间URI
|
||||
* @return this
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public static SoapClient create(String url, SoapProtocol protocol, String namespaceURI) {
|
||||
return new SoapClient(url, protocol, namespaceURI);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造,默认使用soap1.1版本协议
|
||||
*
|
||||
* @param url WS的URL地址
|
||||
*/
|
||||
public SoapClient(String url) {
|
||||
this(url, SoapProtocol.SOAP_1_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param url WS的URL地址
|
||||
* @param protocol 协议版本,见{@link SoapProtocol}
|
||||
*/
|
||||
public SoapClient(String url, SoapProtocol protocol) {
|
||||
this(url, protocol, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param url WS的URL地址
|
||||
* @param protocol 协议版本,见{@link SoapProtocol}
|
||||
* @param namespaceURI 方法上的命名空间URI
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public SoapClient(String url, SoapProtocol protocol, String namespaceURI) {
|
||||
this.url = url;
|
||||
this.namespaceURI = namespaceURI;
|
||||
this.protocol = protocol;
|
||||
init(protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param protocol 协议版本枚举,见{@link SoapProtocol}
|
||||
* @return this
|
||||
*/
|
||||
public SoapClient init(SoapProtocol protocol) {
|
||||
// 创建消息工厂
|
||||
try {
|
||||
this.factory = MessageFactory.newInstance(protocol.getValue());
|
||||
// 根据消息工厂创建SoapMessage
|
||||
this.message = factory.createMessage();
|
||||
} catch (SOAPException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置SOAP客户端,用于客户端复用
|
||||
*
|
||||
* <p>
|
||||
* 重置后需调用serMethod方法重新指定请求方法,并调用setParam方法重新定义参数
|
||||
*
|
||||
* @return this
|
||||
* @since 4.6.7
|
||||
*/
|
||||
public SoapClient reset() {
|
||||
try {
|
||||
this.message = factory.createMessage();
|
||||
} catch (SOAPException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
}
|
||||
this.methodEle = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置编码
|
||||
*
|
||||
* @param charset 编码
|
||||
* @return this
|
||||
* @see #charset(Charset)
|
||||
*/
|
||||
public SoapClient setCharset(Charset charset) {
|
||||
return this.charset(charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoapClient charset(Charset charset) {
|
||||
super.charset(charset);
|
||||
try {
|
||||
this.message.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, this.charset());
|
||||
this.message.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
|
||||
} catch (SOAPException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Webservice请求地址
|
||||
*
|
||||
* @param url Webservice请求地址
|
||||
* @return this
|
||||
*/
|
||||
public SoapClient setUrl(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
|
||||
*
|
||||
* @param name 头信息标签名
|
||||
* @param actorURI 中间的消息接收者
|
||||
* @param roleUri Role的URI
|
||||
* @param mustUnderstand 标题项对于要对其进行处理的接收者来说是强制的还是可选的
|
||||
* @param relay relay属性
|
||||
* @return {@link SOAPHeaderElement}
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public SOAPHeaderElement addSOAPHeader(QName name, String actorURI, String roleUri, Boolean mustUnderstand, Boolean relay) {
|
||||
final SOAPHeaderElement ele = addSOAPHeader(name);
|
||||
try {
|
||||
if (StrUtil.isNotBlank(roleUri)) {
|
||||
ele.setRole(roleUri);
|
||||
}
|
||||
if (null != relay) {
|
||||
ele.setRelay(relay);
|
||||
}
|
||||
} catch (SOAPException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(actorURI)) {
|
||||
ele.setActor(actorURI);
|
||||
}
|
||||
if (null != mustUnderstand) {
|
||||
ele.setMustUnderstand(mustUnderstand);
|
||||
}
|
||||
|
||||
return ele;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
|
||||
*
|
||||
* @param localName 头节点名称
|
||||
* @return {@link SOAPHeaderElement}
|
||||
* @since 5.4.7
|
||||
*/
|
||||
public SOAPHeaderElement addSOAPHeader(String localName) {
|
||||
return addSOAPHeader(new QName(localName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
|
||||
*
|
||||
* @param localName 头节点名称
|
||||
* @param value 头节点的值
|
||||
* @return {@link SOAPHeaderElement}
|
||||
* @since 5.4.7
|
||||
*/
|
||||
public SOAPHeaderElement addSOAPHeader(String localName, String value) {
|
||||
final SOAPHeaderElement soapHeaderElement = addSOAPHeader(localName);
|
||||
soapHeaderElement.setTextContent(value);
|
||||
return soapHeaderElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
|
||||
*
|
||||
* @param name 头节点名称
|
||||
* @return {@link SOAPHeaderElement}
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public SOAPHeaderElement addSOAPHeader(QName name) {
|
||||
SOAPHeaderElement ele;
|
||||
try {
|
||||
ele = this.message.getSOAPHeader().addHeaderElement(name);
|
||||
} catch (SOAPException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
}
|
||||
return ele;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求方法
|
||||
*
|
||||
* @param name 方法名及其命名空间
|
||||
* @param params 参数
|
||||
* @param useMethodPrefix 是否使用方法的命名空间前缀
|
||||
* @return this
|
||||
*/
|
||||
public SoapClient setMethod(Name name, Map<String, Object> params, boolean useMethodPrefix) {
|
||||
return setMethod(new QName(name.getURI(), name.getLocalName(), name.getPrefix()), params, useMethodPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求方法
|
||||
*
|
||||
* @param name 方法名及其命名空间
|
||||
* @param params 参数
|
||||
* @param useMethodPrefix 是否使用方法的命名空间前缀
|
||||
* @return this
|
||||
*/
|
||||
public SoapClient setMethod(QName name, Map<String, Object> params, boolean useMethodPrefix) {
|
||||
setMethod(name);
|
||||
final String prefix = useMethodPrefix ? name.getPrefix() : null;
|
||||
final SOAPBodyElement methodEle = this.methodEle;
|
||||
for (Entry<String, Object> entry : MapUtil.wrap(params)) {
|
||||
setParam(methodEle, entry.getKey(), entry.getValue(), prefix);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求方法<br>
|
||||
* 方法名自动识别前缀,前缀和方法名使用“:”分隔<br>
|
||||
* 当识别到前缀后,自动添加xmlns属性,关联到默认的namespaceURI
|
||||
*
|
||||
* @param methodName 方法名
|
||||
* @return this
|
||||
*/
|
||||
public SoapClient setMethod(String methodName) {
|
||||
return setMethod(methodName, ObjectUtil.defaultIfNull(this.namespaceURI, XMLConstants.NULL_NS_URI));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求方法<br>
|
||||
* 方法名自动识别前缀,前缀和方法名使用“:”分隔<br>
|
||||
* 当识别到前缀后,自动添加xmlns属性,关联到传入的namespaceURI
|
||||
*
|
||||
* @param methodName 方法名(可有前缀也可无)
|
||||
* @param namespaceURI 命名空间URI
|
||||
* @return this
|
||||
*/
|
||||
public SoapClient setMethod(String methodName, String namespaceURI) {
|
||||
final List<String> methodNameList = StrUtil.split(methodName, ':');
|
||||
final QName qName;
|
||||
if (2 == methodNameList.size()) {
|
||||
qName = new QName(namespaceURI, methodNameList.get(1), methodNameList.get(0));
|
||||
} else {
|
||||
qName = new QName(namespaceURI, methodName);
|
||||
}
|
||||
return setMethod(qName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求方法
|
||||
*
|
||||
* @param name 方法名及其命名空间
|
||||
* @return this
|
||||
*/
|
||||
public SoapClient setMethod(QName name) {
|
||||
try {
|
||||
this.methodEle = this.message.getSOAPBody().addBodyElement(name);
|
||||
} catch (SOAPException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方法参数,使用方法的前缀
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param value 参数值,可以是字符串或Map或{@link SOAPElement}
|
||||
* @return this
|
||||
*/
|
||||
public SoapClient setParam(String name, Object value) {
|
||||
return setParam(name, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方法参数
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param value 参数值,可以是字符串或Map或{@link SOAPElement}
|
||||
* @param useMethodPrefix 是否使用方法的命名空间前缀
|
||||
* @return this
|
||||
*/
|
||||
public SoapClient setParam(String name, Object value, boolean useMethodPrefix) {
|
||||
setParam(this.methodEle, name, value, useMethodPrefix ? this.methodEle.getPrefix() : null);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置参数,使用方法的前缀
|
||||
*
|
||||
* @param params 参数列表
|
||||
* @return this
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public SoapClient setParams(Map<String, Object> params) {
|
||||
return setParams(params, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置参数
|
||||
*
|
||||
* @param params 参数列表
|
||||
* @param useMethodPrefix 是否使用方法的命名空间前缀
|
||||
* @return this
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public SoapClient setParams(Map<String, Object> params, boolean useMethodPrefix) {
|
||||
for (Entry<String, Object> entry : MapUtil.wrap(params)) {
|
||||
setParam(entry.getKey(), entry.getValue(), useMethodPrefix);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方法节点<br>
|
||||
* 用于创建子节点等操作
|
||||
*
|
||||
* @return {@link SOAPBodyElement}
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public SOAPBodyElement getMethodEle() {
|
||||
return this.methodEle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SOAP消息对象 {@link SOAPMessage}
|
||||
*
|
||||
* @return {@link SOAPMessage}
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public SOAPMessage getMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SOAP请求消息
|
||||
*
|
||||
* @param pretty 是否格式化
|
||||
* @return 消息字符串
|
||||
*/
|
||||
public String getMsgStr(boolean pretty) {
|
||||
return SoapUtil.toString(this.message, pretty, this.charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将SOAP消息的XML内容输出到流
|
||||
*
|
||||
* @param out 输出流
|
||||
* @return this
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public SoapClient write(OutputStream out) {
|
||||
try {
|
||||
this.message.writeTo(out);
|
||||
} catch (SOAPException | IOException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置超时,单位:毫秒<br>
|
||||
* 超时包括:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 连接超时
|
||||
* 2. 读取响应超时
|
||||
* </pre>
|
||||
*
|
||||
* @param milliseconds 超时毫秒数
|
||||
* @return this
|
||||
* @see #setConnectionTimeout(int)
|
||||
* @see #setReadTimeout(int)
|
||||
*/
|
||||
public SoapClient timeout(int milliseconds) {
|
||||
setConnectionTimeout(milliseconds);
|
||||
setReadTimeout(milliseconds);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置连接超时,单位:毫秒
|
||||
*
|
||||
* @param milliseconds 超时毫秒数
|
||||
* @return this
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public SoapClient setConnectionTimeout(int milliseconds) {
|
||||
this.connectionTimeout = milliseconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置连接超时,单位:毫秒
|
||||
*
|
||||
* @param milliseconds 超时毫秒数
|
||||
* @return this
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public SoapClient setReadTimeout(int milliseconds) {
|
||||
this.readTimeout = milliseconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Webservice请求,即发送SOAP内容
|
||||
*
|
||||
* @return 返回结果
|
||||
*/
|
||||
public SOAPMessage sendForMessage() {
|
||||
final aiyh.utils.tool.cn.hutool.http.HttpResponse res = sendForResponse();
|
||||
final MimeHeaders headers = new MimeHeaders();
|
||||
for (Entry<String, List<String>> entry : res.headers().entrySet()) {
|
||||
if (StrUtil.isNotEmpty(entry.getKey())) {
|
||||
headers.setHeader(entry.getKey(), CollUtil.get(entry.getValue(), 0));
|
||||
}
|
||||
}
|
||||
try {
|
||||
return this.factory.createMessage(headers, res.bodyStream());
|
||||
} catch (IOException | SOAPException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
} finally {
|
||||
IoUtil.close(res);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Webservice请求,即发送SOAP内容
|
||||
*
|
||||
* @return 返回结果
|
||||
*/
|
||||
public String send() {
|
||||
return send(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Webservice请求,即发送SOAP内容
|
||||
*
|
||||
* @param pretty 是否格式化
|
||||
* @return 返回结果
|
||||
*/
|
||||
public String send(boolean pretty) {
|
||||
final String body = sendForResponse().body();
|
||||
return pretty ? XmlUtil.format(body) : body;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 发送请求,获取异步响应
|
||||
*
|
||||
* @return 响应对象
|
||||
*/
|
||||
public HttpResponse sendForResponse() {
|
||||
return HttpRequest.post(this.url)//
|
||||
.setFollowRedirects(true)//
|
||||
.setConnectionTimeout(this.connectionTimeout)
|
||||
.setReadTimeout(this.readTimeout)
|
||||
.contentType(getXmlContentType())//
|
||||
.header(this.headers())
|
||||
.body(getMsgStr(false))//
|
||||
.executeAsync();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求的Content-Type,附加编码信息
|
||||
*
|
||||
* @return 请求的Content-Type
|
||||
*/
|
||||
private String getXmlContentType() {
|
||||
switch (this.protocol) {
|
||||
case SOAP_1_1:
|
||||
return CONTENT_TYPE_SOAP11_TEXT_XML.concat(this.charset.toString());
|
||||
case SOAP_1_2:
|
||||
return CONTENT_TYPE_SOAP12_SOAP_XML.concat(this.charset.toString());
|
||||
default:
|
||||
throw new SoapRuntimeException("Unsupported protocol: {}", this.protocol);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方法参数
|
||||
*
|
||||
* @param ele 方法节点
|
||||
* @param name 参数名
|
||||
* @param value 参数值
|
||||
* @param prefix 命名空间前缀, {@code null}表示不使用前缀
|
||||
* @return {@link SOAPElement}子节点
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static SOAPElement setParam(SOAPElement ele, String name, Object value, String prefix) {
|
||||
final SOAPElement childEle;
|
||||
try {
|
||||
if (StrUtil.isNotBlank(prefix)) {
|
||||
childEle = ele.addChildElement(name, prefix);
|
||||
} else {
|
||||
childEle = ele.addChildElement(name);
|
||||
}
|
||||
} catch (SOAPException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
}
|
||||
|
||||
if (null != value) {
|
||||
if (value instanceof SOAPElement) {
|
||||
// 单个子节点
|
||||
try {
|
||||
ele.addChildElement((SOAPElement) value);
|
||||
} catch (SOAPException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
}
|
||||
} else if (value instanceof Map) {
|
||||
// 多个字节点
|
||||
Entry entry;
|
||||
for (Object obj : ((Map) value).entrySet()) {
|
||||
entry = (Entry) obj;
|
||||
setParam(childEle, entry.getKey().toString(), entry.getValue(), prefix);
|
||||
}
|
||||
} else {
|
||||
// 单个值
|
||||
childEle.setValue(value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return childEle;
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------------- Private method end
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.webservice;
|
||||
|
||||
import javax.xml.soap.SOAPConstants;
|
||||
|
||||
/**
|
||||
* SOAP协议版本枚举
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public enum SoapProtocol {
|
||||
/** SOAP 1.1协议 */
|
||||
SOAP_1_1(SOAPConstants.SOAP_1_1_PROTOCOL),
|
||||
/** SOAP 1.2协议 */
|
||||
SOAP_1_2(SOAPConstants.SOAP_1_2_PROTOCOL);
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param value {@link SOAPConstants} 中的协议版本值
|
||||
*/
|
||||
SoapProtocol(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* 获取版本值信息
|
||||
*
|
||||
* @return 版本值信息
|
||||
*/
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.webservice;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* SOAP异常
|
||||
*
|
||||
* @author xiaoleilu
|
||||
*/
|
||||
public class SoapRuntimeException extends RuntimeException {
|
||||
private static final long serialVersionUID = 8247610319171014183L;
|
||||
|
||||
public SoapRuntimeException(Throwable e) {
|
||||
super(e.getMessage(), e);
|
||||
}
|
||||
|
||||
public SoapRuntimeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SoapRuntimeException(String messageTemplate, Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params));
|
||||
}
|
||||
|
||||
public SoapRuntimeException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
|
||||
public SoapRuntimeException(Throwable throwable, String messageTemplate, Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params), throwable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package aiyh.utils.tool.cn.hutool.http.webservice;
|
||||
|
||||
import aiyh.utils.tool.cn.hutool.core.exceptions.UtilException;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.CharsetUtil;
|
||||
import aiyh.utils.tool.cn.hutool.core.util.XmlUtil;
|
||||
|
||||
import javax.xml.soap.SOAPException;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* SOAP相关工具类
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.5.7
|
||||
*/
|
||||
public class SoapUtil {
|
||||
|
||||
/**
|
||||
* 创建SOAP客户端,默认使用soap1.1版本协议
|
||||
*
|
||||
* @param url WS的URL地址
|
||||
* @return {@link aiyh.utils.tool.cn.hutool.http.webservice.SoapClient}
|
||||
*/
|
||||
public static aiyh.utils.tool.cn.hutool.http.webservice.SoapClient createClient(String url) {
|
||||
return aiyh.utils.tool.cn.hutool.http.webservice.SoapClient.create(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建SOAP客户端
|
||||
*
|
||||
* @param url WS的URL地址
|
||||
* @param protocol 协议,见{@link SoapProtocol}
|
||||
* @return {@link aiyh.utils.tool.cn.hutool.http.webservice.SoapClient}
|
||||
*/
|
||||
public static aiyh.utils.tool.cn.hutool.http.webservice.SoapClient createClient(String url, SoapProtocol protocol) {
|
||||
return aiyh.utils.tool.cn.hutool.http.webservice.SoapClient.create(url, protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建SOAP客户端
|
||||
*
|
||||
* @param url WS的URL地址
|
||||
* @param protocol 协议,见{@link SoapProtocol}
|
||||
* @param namespaceURI 方法上的命名空间URI
|
||||
* @return {@link aiyh.utils.tool.cn.hutool.http.webservice.SoapClient}
|
||||
* @since 4.5.6
|
||||
*/
|
||||
public static aiyh.utils.tool.cn.hutool.http.webservice.SoapClient createClient(String url, SoapProtocol protocol, String namespaceURI) {
|
||||
return SoapClient.create(url, protocol, namespaceURI);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SOAPMessage} 转为字符串
|
||||
*
|
||||
* @param message SOAP消息对象
|
||||
* @param pretty 是否格式化
|
||||
* @return SOAP XML字符串
|
||||
*/
|
||||
public static String toString(SOAPMessage message, boolean pretty) {
|
||||
return toString(message, pretty, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SOAPMessage} 转为字符串
|
||||
*
|
||||
* @param message SOAP消息对象
|
||||
* @param pretty 是否格式化
|
||||
* @param charset 编码
|
||||
* @return SOAP XML字符串
|
||||
* @since 4.5.7
|
||||
*/
|
||||
public static String toString(SOAPMessage message, boolean pretty, Charset charset) {
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try {
|
||||
message.writeTo(out);
|
||||
} catch (SOAPException | IOException e) {
|
||||
throw new SoapRuntimeException(e);
|
||||
}
|
||||
String messageToString;
|
||||
try {
|
||||
messageToString = out.toString(charset.toString());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new UtilException(e);
|
||||
}
|
||||
return pretty ? XmlUtil.format(messageToString) : messageToString;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* Webservice客户端封装实现
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
package aiyh.utils.tool.cn.hutool.http.webservice;
|
|
@ -6,6 +6,7 @@ import com.api.bokang.xiao.zscq.service.ReserveService;
|
|||
import com.api.bokang.xiao.zscq.service.impl.ReserveServiceImpl;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import org.apache.log4j.Logger;
|
||||
import weaver.bokang.xiao.zscq.store.TableNameStore;
|
||||
import weaver.file.ImageFileManager;
|
||||
import weaver.hrm.HrmUserVarify;
|
||||
import weaver.hrm.User;
|
||||
|
@ -17,7 +18,9 @@ import javax.ws.rs.*;
|
|||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.StreamingOutput;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -48,77 +51,68 @@ public class ReserveSelectController {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public String reserveSelect(@Context HttpServletRequest request, @Context HttpServletResponse response, @RequestBody Map<String,Object> param) {
|
||||
try{
|
||||
log.info("====== into getReportData success =======");
|
||||
log.info("====== into reserveSelect success =======");
|
||||
log.info("param:"+param);
|
||||
User loginUser = HrmUserVarify.getUser(request, response);
|
||||
List<Map<String, Object>> result = reserveService.reserveSelect(param);
|
||||
List<Map<String, Object>> result = reserveService.reserveTrigger(param);
|
||||
return ApiResult.success(result);
|
||||
}catch (Exception e){
|
||||
log.error("获取搜索组件信息 ==> "+ Util.getErrString(e));
|
||||
log.error("反选执行出现异常 reserveSelect execute error ==> "+ Util.getErrString(e));
|
||||
return ApiResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
//@GET
|
||||
//@Path("/batch")
|
||||
//@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
//public void downloadFiles(@QueryParam("ids") String ids, @Context HttpServletResponse response) {
|
||||
// try {
|
||||
// log.info("Start downloading files: {}"+ids);
|
||||
// // 解析文件ID列表
|
||||
// List<Long> idList = Arrays.stream(ids.split(","))
|
||||
// .map(Long::parseLong)
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// // 生成压缩文件名
|
||||
// String zipFileName = "attachments.zip";
|
||||
//
|
||||
// // 设置响应头,告诉浏览器该响应体是一个附件,浏览器会自动下载该响应体
|
||||
// response.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
// response.setHeader("Content-Disposition", "attachment; filename=\"" + zipFileName + "\"");
|
||||
//
|
||||
// // 创建压缩输出流
|
||||
// try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
|
||||
//
|
||||
// // 遍历文件ID列表,将对应的文件加入到压缩文件中
|
||||
// for (Long id : idList) {
|
||||
// // 通过ID获取文件信息
|
||||
// WeaverFile file = WeaverFileUtil.getFileMsgById(id);
|
||||
//
|
||||
// // 获取文件名和后缀名
|
||||
// String fileName = file.getName();
|
||||
// String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
//
|
||||
// // 创建一个ZipEntry,表示压缩文件中的一个文件
|
||||
// ZipEntry zipEntry = new ZipEntry(fileName);
|
||||
// zipEntry.setSize(file.getSize());
|
||||
// zipEntry.setTime(System.currentTimeMillis());
|
||||
//
|
||||
// // 将ZipEntry添加到压缩输出流中
|
||||
// zipOutputStream.putNextEntry(zipEntry);
|
||||
//
|
||||
// // 将文件内容写入到压缩输出流中
|
||||
// byte[] buffer = new byte[BUFFER_SIZE];
|
||||
// int len;
|
||||
// try (InputStream inputStream = file.getInputStream()) {
|
||||
// while ((len = inputStream.read(buffer)) > 0) {
|
||||
// zipOutputStream.write(buffer, 0, len);
|
||||
// }
|
||||
// }
|
||||
// zipOutputStream.closeEntry();
|
||||
// }
|
||||
//
|
||||
// // 刷新压缩输出流
|
||||
// zipOutputStream.flush();
|
||||
// }
|
||||
// log.info("Finish downloading files: {}"+ids);
|
||||
// } catch (Exception e) {
|
||||
// log.error("下载附件异常: {}"+Util.getErrString(e));
|
||||
// // 如果出现异常,返回一个空的响应体
|
||||
// response.reset();
|
||||
// response.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
// response.setContentLength(0);
|
||||
// }
|
||||
//}
|
||||
@GET
|
||||
@Path("/batchDownload")
|
||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
public Response downloadBatchFiles(@QueryParam("datePicker") String datePicker,
|
||||
@QueryParam("checkResult") String checkResult,
|
||||
@QueryParam("checkResultShow") String checkResultShow) {
|
||||
log.info("====== into downloadBatchFiles success =======");
|
||||
log.info(String.format("====== datePicker:[%s] checkResult:[%s] checkResultShow:[%s] =======",datePicker,checkResult,checkResultShow));
|
||||
Map<String,Object> param = new HashMap<>(8);
|
||||
param.put("datePicker",datePicker);
|
||||
param.put("checkResult",checkResult);
|
||||
param.put("checkResultShow",checkResultShow);
|
||||
String zipFileName = reserveService.getFileName(param) + ".zip";
|
||||
StreamingOutput streamingOutput = outputStream -> {
|
||||
try {
|
||||
reserveService.batchDownload(param, outputStream);
|
||||
} catch (Exception e) {
|
||||
log.error("下载文件异常 download zip error ==>"+Util.getErrString(e));
|
||||
}
|
||||
};
|
||||
log.info("zip file name ==>"+zipFileName);
|
||||
return Response.ok(streamingOutput, MediaType.APPLICATION_OCTET_STREAM)
|
||||
.header("Content-Disposition", "attachment; filename=\"" + zipFileName + "\"")
|
||||
.build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/refreshStore")
|
||||
public String refreshStore(@Context HttpServletRequest request, @Context HttpServletResponse response){
|
||||
try{
|
||||
log.info("====== into refreshStore success =======");
|
||||
TableNameStore.getInstance().refresh();
|
||||
return ApiResult.successNoData();
|
||||
}catch (Exception e){
|
||||
log.error("refreshStore execute error ==> "+ Util.getErrString(e));
|
||||
return ApiResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/doRepossessedSign")
|
||||
public String doRepossessedSign(@QueryParam("requestId") String requestId){
|
||||
try{
|
||||
log.info("====== into doRepossessedSign success =======");
|
||||
log.info("requestId =>"+requestId);
|
||||
new ReserveServiceImpl().doRepossessedSign(Util.getIntValue(requestId),new User(1));
|
||||
return ApiResult.successNoData();
|
||||
}catch (Exception e){
|
||||
log.error("refreshStore execute error ==> "+ Util.getErrString(e));
|
||||
return ApiResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package com.api.bokang.xiao.zscq.entity;
|
||||
|
||||
import aiyh.utils.annotation.recordset.SqlOracleDbFieldAnn;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @ClassName SendFileEntity
|
||||
* @Author 肖博亢
|
||||
* @Date 2023/4/23 10:10
|
||||
* @Description <h1></h1>
|
||||
**/
|
||||
@Data
|
||||
public class SendFileEntity {
|
||||
|
||||
@SqlOracleDbFieldAnn(value = "ID")
|
||||
private Integer id;
|
||||
|
||||
@SqlOracleDbFieldAnn(value = "DEPART_ID")
|
||||
private Integer departId;
|
||||
|
||||
@SqlOracleDbFieldAnn(value = "DEPART_NAME")
|
||||
private String departName;
|
||||
|
||||
@SqlOracleDbFieldAnn(value = "SQH")
|
||||
private String requestNumber;
|
||||
|
||||
private WeaverFile weaverFile;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.api.bokang.xiao.zscq.entity;
|
||||
|
||||
import aiyh.utils.annotation.recordset.SqlOracleDbFieldAnn;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @ClassName WeaverFile
|
||||
* @Author 肖博亢
|
||||
* @Date 2023/4/23 10:09
|
||||
* @Description <h1></h1>
|
||||
**/
|
||||
@Data
|
||||
public class WeaverFile {
|
||||
|
||||
@SqlOracleDbFieldAnn(value = "IMAGEFILEID")
|
||||
private Integer imageFileId;
|
||||
|
||||
@SqlOracleDbFieldAnn(value = "DOCID")
|
||||
private Integer docId;
|
||||
|
||||
@SqlOracleDbFieldAnn(value = "FILESIZE")
|
||||
private Integer fileSize;
|
||||
|
||||
@SqlOracleDbFieldAnn(value = "IMAGEFILENAME")
|
||||
private String fileName;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.api.bokang.xiao.zscq.mapper;
|
||||
|
||||
import aiyh.utils.annotation.recordset.*;
|
||||
import com.api.bokang.xiao.zscq.entity.SendFileEntity;
|
||||
import com.api.bokang.xiao.zscq.entity.WeaverFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassName QueryMapper
|
||||
* @Author 肖博亢
|
||||
* @Date 2023/4/23 10:14
|
||||
* @Description <h1></h1>
|
||||
**/
|
||||
@SqlMapper
|
||||
public interface QueryMapper {
|
||||
|
||||
/**
|
||||
* <h2>查询附件下载列表</h2>
|
||||
* @param param 参数
|
||||
* @return 附件信息列表
|
||||
*/
|
||||
@Select("select gjj.id as id,depart.id as depart_id,depart.DEPARTMENTNAME as depart_name,xgfj,sqh " +
|
||||
" from uf_gjjtb gjj " +
|
||||
" inner join hrmdepartment depart on gjj.xfqj = depart.id " +
|
||||
" where concat(',',concat(sjpcdxk,',')) like concat('%,',concat(#{datePicker},',%')) " +
|
||||
" and hcqkdx = #{checkResult} and gjj.xgfj is not null ")
|
||||
@Associations( @Association(property = "weaverFile",column = "xgfj",id = @Id(value = Integer.class,methodId = 1)))
|
||||
List<SendFileEntity> queryDownloadList(Map<String,Object> param);
|
||||
|
||||
/**
|
||||
* <h2>查询附件信息</h2>
|
||||
* @param docId docId
|
||||
* @return 附件信息
|
||||
*/
|
||||
@AssociationMethod(value = 1)
|
||||
@Select("select dm.docid,dm.imagefileid,dm.imagefilename,file.filesize " +
|
||||
" from docimagefile dm inner join imagefile file on dm.imagefileid = file.imagefileid" +
|
||||
" where docid = #{docId}")
|
||||
WeaverFile queryFile(@ParamMapper("id")Integer docId);
|
||||
|
||||
/**
|
||||
* <h2>获取下拉框信息</h2>
|
||||
* @param tableName 表名
|
||||
* @param fieldName 字段名
|
||||
* @return 下拉框信息
|
||||
*/
|
||||
@Select("select selectvalue,selectname " +
|
||||
" from workflow_selectitem se " +
|
||||
" inner join workflow_billfield bf on se.fieldid = bf.id " +
|
||||
" inner join workflow_bill bi on bf.billid = bi.id " +
|
||||
" where tablename = #{tableName} and bf.fieldname = #{fieldName} ")
|
||||
List<Map<String,Object>> querySelectItem(@ParamMapper("tableName") String tableName,@ParamMapper("fieldName") String fieldName);
|
||||
|
||||
}
|
|
@ -19,7 +19,7 @@ public interface ReserveSelectMapper {
|
|||
* @param requestId 流程id
|
||||
* @return 操作人信息
|
||||
*/
|
||||
@Select("select operator userId,operatortype userType from workflow_requestlog where requestid=#{requestId}" +
|
||||
@Select("select operator userid,operatortype usertype from workflow_requestlog where requestid=#{requestId}" +
|
||||
" and (logtype='2' or logtype='0' or logtype='3' or logtype='e') " +
|
||||
" and exists(select 1 from workflow_currentoperator where requestid=workflow_requestlog.requestid and userid=workflow_requestlog.operator and usertype=workflow_requestlog.operatortype and isremark='2' and preisremark='0' and operatedate is not null and operatedate>' ') " +
|
||||
" group by operator,operatortype order by max(logid) desc")
|
||||
|
@ -30,7 +30,7 @@ public interface ReserveSelectMapper {
|
|||
* @param requestId 流程id
|
||||
* @return 操作人信息
|
||||
*/
|
||||
@Select("select userid userId,usertype userType from workflow_currentoperator where requestid = #{requestId} and isremark = '2' and preisremark='0' and operatedate is not null and operatedate>' ' order by operatedate desc ,operatetime desc")
|
||||
@Select("select userid,usertype from workflow_currentoperator where requestid = #{requestId} and isremark = '2' and preisremark='0' and operatedate is not null and operatedate>' ' order by operatedate desc ,operatetime desc")
|
||||
Map<String,Integer> queryOperator(@ParamMapper("requestId")String requestId);
|
||||
|
||||
/**
|
||||
|
@ -38,17 +38,26 @@ public interface ReserveSelectMapper {
|
|||
* @param param 参数信息
|
||||
* @return 建模数据
|
||||
*/
|
||||
@Select("select id, $t{applicationNoField}, $t{workflowInfoField}, $t{checkResultField} from $t{modeTableName} where $t{dateField} = #{datePicker}")
|
||||
@Select("select id, $t{applicationNoField}, $t{workflowInfoField}, $t{checkResultField} from $t{modeTableName} where concat(',',concat($t{dateField},',')) like #{datePicker} and ($t{markField} <> 0 or $t{markField} is not null)")
|
||||
@CaseConversion(value = false)
|
||||
List<Map<String, Object>> queryModeList(Map<String, Object> param);
|
||||
|
||||
/**
|
||||
* <h2>更新检查结果</h2>
|
||||
* @param param 参数信息
|
||||
* @return 更新结果
|
||||
*/
|
||||
@Update("update $t{modeTableName} set $t{markField} = 1 " +
|
||||
" where concat(',',concat($t{dateField},',')) like #{datePicker}")
|
||||
boolean updateModeDataStatus(@ParamMapper("param") Map<String, Object> param);
|
||||
|
||||
/**
|
||||
* <h2>更新检查结果</h2>
|
||||
* @param forceOverList 强制归档流程id集合
|
||||
* @param param 参数信息
|
||||
* @return 更新结果
|
||||
*/
|
||||
@Update("update $t{param.modeTableName} set $t{param.checkResultField} = #{param.repossessedValue} " +
|
||||
@Update("update $t{param.modeTableName} set $t{param.markField} = #{param.repossessedValue} " +
|
||||
" where $t{param.workflowInfoField} in (${doRepossessedList})")
|
||||
boolean updateRepossessed(@ParamMapper("doRepossessedList") List<String> forceOverList,
|
||||
@ParamMapper("param") Map<String, Object> param);
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.api.bokang.xiao.zscq.service;
|
|||
import aiyh.utils.Util;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -22,4 +23,26 @@ public interface ReserveService {
|
|||
* @return 操作结果
|
||||
*/
|
||||
List<Map<String,Object>> reserveSelect(Map<String,Object> param);
|
||||
|
||||
/**
|
||||
* <h2>反选操作</h2>
|
||||
* @param param 参数信息
|
||||
* @return 操作结果
|
||||
*/
|
||||
List<Map<String,Object>> reserveTrigger(Map<String,Object> param);
|
||||
|
||||
/**
|
||||
* <h2>将附件信息合并</h2>
|
||||
* @param param 查询参数
|
||||
* @param outputStream 输出流
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
void batchDownload(Map<String,Object> param, OutputStream outputStream) throws Exception;
|
||||
|
||||
/**
|
||||
* <h2>获取文件名</h2>
|
||||
* @param param 参数信息
|
||||
* @return 文件名
|
||||
*/
|
||||
String getFileName(Map<String,Object> param);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,27 @@
|
|||
package com.api.bokang.xiao.zscq.service.impl;
|
||||
|
||||
import aiyh.utils.Util;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.api.bokang.xiao.zscq.entity.SendFileEntity;
|
||||
import com.api.bokang.xiao.zscq.entity.WeaverFile;
|
||||
import com.api.bokang.xiao.zscq.mapper.QueryMapper;
|
||||
import com.api.bokang.xiao.zscq.mapper.ReserveSelectMapper;
|
||||
import com.api.bokang.xiao.zscq.service.ReserveService;
|
||||
import weaver.bokang.xiao.zscq.config.service.ModeChangeService;
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.file.ImageFileManager;
|
||||
import weaver.hrm.User;
|
||||
import weaver.workflow.workflow.RequestForceDrawBack;
|
||||
import weaver.workflow.workflow.WfForceDrawBack;
|
||||
import weaver.workflow.workflow.WfForceOver;
|
||||
import weaver.workflow.workflow.WfFunctionManageUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -23,6 +34,8 @@ public class ReserveServiceImpl implements ReserveService {
|
|||
|
||||
private final ReserveSelectMapper reserveSelectMapper = Util.getMapper(ReserveSelectMapper.class);
|
||||
|
||||
private final QueryMapper queryMapper = Util.getMapper(QueryMapper.class);
|
||||
|
||||
private final WfForceOver wfForceOver = new WfForceOver();
|
||||
|
||||
private final WfFunctionManageUtil wfFunctionManageUtil = new WfFunctionManageUtil();
|
||||
|
@ -30,6 +43,11 @@ public class ReserveServiceImpl implements ReserveService {
|
|||
private final WfForceDrawBack wfForceDrawBack = new WfForceDrawBack();
|
||||
private final RequestForceDrawBack requestForceDrawBack = new RequestForceDrawBack();
|
||||
|
||||
private final ModeChangeService modeChangeService = new ModeChangeService();
|
||||
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
|
||||
/**
|
||||
* <h2>流程强制收回</>
|
||||
* @param requestIdList 流程id集合
|
||||
|
@ -51,15 +69,19 @@ public class ReserveServiceImpl implements ReserveService {
|
|||
* @param user 用户信息
|
||||
* @return 操作结果
|
||||
*/
|
||||
private boolean doRepossessedSign(int requestId,User user){
|
||||
public boolean doRepossessedSign(int requestId,User user){
|
||||
//查询最后一个操作者
|
||||
Map<String, Integer> operateInfo = reserveSelectMapper.queryRequestMsg(String.valueOf(requestId));
|
||||
log.info(" doRepossessedSign operateInfo ==>"+operateInfo);
|
||||
if(Objects.isNull(operateInfo)){
|
||||
operateInfo = reserveSelectMapper.queryOperator(String.valueOf(requestId));
|
||||
}
|
||||
int tempUser = operateInfo.get("userId");
|
||||
int tempUserType = operateInfo.get("userType");
|
||||
log.info(" doRepossessedSign operateInfo ==>"+operateInfo);
|
||||
if(Objects.isNull(operateInfo)){
|
||||
log.error(String.format("流程 requestId:[%s] 操作者 operateInfo no find 流程可能未归档 !!!",requestId));
|
||||
return false;
|
||||
}
|
||||
int tempUser = operateInfo.get("userid");
|
||||
int tempUserType = operateInfo.get("usertype");
|
||||
boolean canForceDrawBack = false;
|
||||
if(RequestForceDrawBack.isOldRequest(requestId) == RequestForceDrawBack.OLDDATA){
|
||||
canForceDrawBack = wfForceDrawBack.isHavePurview(requestId, user.getUID(), Integer.parseInt(user.getLogintype()), tempUser, tempUserType);
|
||||
|
@ -68,6 +90,7 @@ public class ReserveServiceImpl implements ReserveService {
|
|||
}
|
||||
if (canForceDrawBack && wfFunctionManageUtil.haveOtherOperationRight(requestId)) {
|
||||
int result = requestForceDrawBack.foreceDrawBack(user, requestId, true, tempUser, tempUserType);
|
||||
log.info(String.format("流程 requestId:[%s] 撤回结果 drawBack result:[%d] message:[%s]",requestId,result,requestForceDrawBack.getMessage()));
|
||||
return requestForceDrawBack.isAddInOperateSuccess();
|
||||
}else{
|
||||
return false;
|
||||
|
@ -97,9 +120,9 @@ public class ReserveServiceImpl implements ReserveService {
|
|||
String checkResult = Util.null2String(modeInfo.get(checkResultField));
|
||||
int requestId = Util.getIntValue(Util.null2String(modeInfo.get(workflowInfoField)));
|
||||
if(checkResult.equals(checkResultValue)){
|
||||
forceOverList.add(requestId+"");
|
||||
}else {
|
||||
doRepossessedList.add(requestId);
|
||||
}else {
|
||||
forceOverList.add(requestId+"");
|
||||
}
|
||||
}
|
||||
log.info(String.format("doRepossessedList ==> %s forceOverList ==> %s",doRepossessedList,forceOverList));
|
||||
|
@ -111,4 +134,91 @@ public class ReserveServiceImpl implements ReserveService {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> reserveTrigger(Map<String, Object> param) {
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
String applicationNoField = Util.null2String(param.get("applicationNoField"));
|
||||
String workflowInfoField = Util.null2String(param.get("workflowInfoField"));
|
||||
String formId = Util.null2String(param.get("formId"));
|
||||
List<Map<String, Object>> modeList = reserveSelectMapper.queryModeList(param);
|
||||
if(Objects.nonNull(modeList) && !modeList.isEmpty()){
|
||||
for (Map<String, Object> modeMap : modeList) {
|
||||
Map<String,Object> dealResult = new HashMap<>();
|
||||
try{
|
||||
modeChangeService.changeOtherMode(modeMap,formId,2);
|
||||
dealResult.put(Util.null2String(modeMap.get(applicationNoField)),true);
|
||||
}catch (Exception e){
|
||||
log.error("执行异常 reserveTrigger error ==>"+modeMap);
|
||||
dealResult.put(Util.null2String(modeMap.get(applicationNoField)),false);
|
||||
}
|
||||
result.add(dealResult);
|
||||
}
|
||||
reserveSelectMapper.updateModeDataStatus(param);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void batchDownload(Map<String,Object> param, OutputStream outputStream) throws IOException {
|
||||
List<SendFileEntity> sendList = queryMapper.queryDownloadList(param);
|
||||
if(Objects.isNull(sendList) || sendList.isEmpty()){
|
||||
log.info("附件列表为空 attachment empty !!!");
|
||||
//throw new CustomerException("附件列表查询为空");
|
||||
return;
|
||||
}
|
||||
log.info("查询到的附件信息 query fileList ==>"+ JSON.toJSONString(sendList));
|
||||
// 1. 将 SendFileEntity 按照 departName 分组
|
||||
Map<String, List<SendFileEntity>> sendMap = sendList.stream().collect(Collectors.groupingBy(SendFileEntity::getDepartName));
|
||||
// 2. 创建 ZipOutputStream
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(outputStream));
|
||||
// 3. 遍历 SendFileEntity
|
||||
for (Map.Entry<String, List<SendFileEntity>> entry : sendMap.entrySet()) {
|
||||
String departName = entry.getKey();
|
||||
List<SendFileEntity> fileList = entry.getValue();
|
||||
// 4. 创建目录
|
||||
ZipEntry dirEntry = new ZipEntry(departName + File.separator);
|
||||
zipOutputStream.putNextEntry(dirEntry);
|
||||
// 5. 将附件信息合并成一个压缩包
|
||||
for (SendFileEntity sendFileEntity : fileList) {
|
||||
WeaverFile fileMsg = sendFileEntity.getWeaverFile();
|
||||
int imageFileId = fileMsg.getImageFileId();
|
||||
String fileName = fileMsg.getFileName();
|
||||
String fileType = fileName.substring(fileName.lastIndexOf("."));
|
||||
String tempFileName = sendFileEntity.getRequestNumber() + fileType;
|
||||
InputStream inputStream = ImageFileManager.getInputStreamById(imageFileId);
|
||||
// 6. 将单个附件写入 ZipOutputStream
|
||||
ZipEntry fileEntry = new ZipEntry(departName + File.separator + tempFileName);
|
||||
zipOutputStream.putNextEntry(fileEntry);
|
||||
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int bytesRead = -1;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
zipOutputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
// 7. 关闭 ZipOutputStream
|
||||
zipOutputStream.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName(Map<String, Object> param) {
|
||||
String fileName = "";
|
||||
List<Map<String, Object>> selectItems = queryMapper.querySelectItem("uf_gjjtb", "sjpcdxk");
|
||||
if(Objects.nonNull(selectItems) && !selectItems.isEmpty()){
|
||||
Map<String, String> map = selectItems.stream().collect(Collectors
|
||||
.toMap(
|
||||
item -> Util.null2String(item.get("selectvalue")),
|
||||
item -> Util.null2String(item.get("selectname"))
|
||||
)
|
||||
);
|
||||
String datePicker = Util.null2String(param.get("datePicker"));
|
||||
String checkResultShow = new String(Util.null2String(param.get("checkResultShow")).getBytes(), StandardCharsets.UTF_8);
|
||||
String datePickerShow = Util.null2String(map.get(datePicker));
|
||||
fileName = datePickerShow + checkResultShow;
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,618 @@
|
|||
package com.api.interfaces.liyi;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.api.interfaces.liyi.common.ApiResult;
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.general.BaseBean;
|
||||
import weaver.general.Util;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Path("/xsd/DataCenterApi")
|
||||
public class DataCenterApi extends BaseBean {
|
||||
|
||||
@GET
|
||||
@Path("/getCompInfo")
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String getCompInfo(@Context HttpServletRequest request, @Context HttpServletResponse response){
|
||||
ApiResult<Map<String,Object>> apiResult = new ApiResult<>();
|
||||
RecordSet rs = new RecordSet();
|
||||
String idCard = Util.null2String(request.getParameter("id_card"));
|
||||
String tableName = getFormId("datacenter_table");
|
||||
HashMap<String,Object> comMap = new HashMap<>();
|
||||
try {
|
||||
if(!idCard.equals("")){
|
||||
String id = "";
|
||||
String sql = "select top 1 * from "+tableName+" where field016 = '"+idCard+"' order by id desc";
|
||||
writeLog("------sql zb------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
if(rs.next()){
|
||||
id = rs.getString("id");
|
||||
String ypgw = rs.getString("field055");
|
||||
String ypgw_xz = getSelectName(tableName,null,"field055",ypgw);
|
||||
String djrq = rs.getString("field007");
|
||||
String xm = rs.getString("field008");
|
||||
String xb = rs.getString("field052");
|
||||
String xb_xz = getSelectName(tableName,null,"field052",xb);
|
||||
String csrq = rs.getString("field010");
|
||||
String mz = rs.getString("field053");
|
||||
String mz_xz = getSelectName(tableName,null,"field053",mz);
|
||||
String jg = rs.getString("field056");
|
||||
String jg_xz = getSelectName(tableName,null,"field056",jg);
|
||||
String hy = rs.getString("field085");
|
||||
String hy_xz = getSelectName(tableName,null,"field085",hy);
|
||||
String zzmm = rs.getString("field054");
|
||||
String zzmm_xz = getSelectName(tableName,null,"field054",zzmm);
|
||||
String sj = rs.getString("field015");
|
||||
String yx = rs.getString("field017");
|
||||
String pro = rs.getString("field077");
|
||||
String city = rs.getString("field078");
|
||||
String qx = rs.getString("field079");
|
||||
String xxdz = rs.getString("field080");
|
||||
String xpro = rs.getString("field081");
|
||||
String xcity = rs.getString("field082");
|
||||
String xqx = rs.getString("field083");
|
||||
String xxxdz = rs.getString("field084");
|
||||
String jjlxr = rs.getString("field020");
|
||||
String jjlxrgx = rs.getString("field086");
|
||||
jjlxrgx = getSelectName(tableName,null,"field086",jjlxrgx);
|
||||
String lxrdh = rs.getString("field022");
|
||||
String english = rs.getString("field023");
|
||||
english = getSelectName(tableName,null,"field023",english);
|
||||
String cert = rs.getString("field061");
|
||||
String eng_fj = rs.getString("field058");
|
||||
String qtyz = rs.getString("field059");
|
||||
String djzs = rs.getString("field062");
|
||||
String qtyz_fj = rs.getString("field060");
|
||||
String zyzg = rs.getString("field063");
|
||||
String zyzgzs = rs.getString("field064");
|
||||
String zyzg_fj = rs.getString("field065");
|
||||
String qtjn = rs.getString("field066");
|
||||
String bgrj = rs.getString("field067");
|
||||
String qtjn_fj = rs.getString("field068");
|
||||
String xqah = rs.getString("field025");
|
||||
String gdxzsq = rs.getString("field026");
|
||||
String qwxzsq = rs.getString("field027");
|
||||
String sbyf = rs.getString("field028");
|
||||
String sbnf = rs.getString("field029");
|
||||
String gzlxdh = rs.getString("field030");
|
||||
String zmr = rs.getString("field031");
|
||||
String zmrgw = rs.getString("field032");
|
||||
String sfjcldht = rs.getString("field033");
|
||||
String sfjlcf = rs.getString("field034");
|
||||
String sfjb = rs.getString("field035");
|
||||
String sfss = rs.getString("field036");
|
||||
String sfyhjkgz = rs.getString("field037");
|
||||
String sfyytj = rs.getString("field038");
|
||||
String sftgbszy = rs.getString("field039");
|
||||
String tjrxm = rs.getString("field040");
|
||||
String tjrgx = rs.getString("field041");
|
||||
String bgsqs = rs.getString("field042");
|
||||
String gxr = rs.getString("field046");
|
||||
String gxrgx = rs.getString("field047");
|
||||
String tbr = rs.getString("field048");
|
||||
String sfty = rs.getString("field069");
|
||||
|
||||
/* update by bokang.xiao */
|
||||
//现居住地址
|
||||
String residentialAddress = rs.getString("field045");
|
||||
//现居地址邮编
|
||||
String residentialPostcode = rs.getString("field104");
|
||||
//家庭住址
|
||||
String familyAddress = rs.getString("field105");
|
||||
//法定联系地址
|
||||
String contactAddress = rs.getString("field106");
|
||||
//法定联系地址邮编
|
||||
String contactPostcode = rs.getString("field107");
|
||||
//紧急联系人地址
|
||||
String emergencyContactAddress = rs.getString("field108");
|
||||
//一寸照片
|
||||
String headPicture = rs.getString("field109");
|
||||
//公积金账户及所在城市
|
||||
String providentFundAccount = rs.getString("field110");
|
||||
//开户行
|
||||
String openingBank = rs.getString("field111");
|
||||
//银行卡号
|
||||
String bankCardNo = rs.getString("field112");
|
||||
|
||||
comMap.put("residentialAddress",residentialAddress);
|
||||
comMap.put("residentialPostcode",residentialPostcode);
|
||||
comMap.put("familyAddress",familyAddress);
|
||||
comMap.put("contactAddress",contactAddress);
|
||||
comMap.put("contactPostcode",contactPostcode);
|
||||
comMap.put("emergencyContactAddress",emergencyContactAddress);
|
||||
comMap.put("providentFundAccount",providentFundAccount);
|
||||
comMap.put("openingBank",openingBank);
|
||||
comMap.put("bankCardNo",bankCardNo);
|
||||
comMap.put("headPicture",headPicture);
|
||||
/* update by bokang.xiao */
|
||||
|
||||
comMap.put("ypgw",ypgw);
|
||||
comMap.put("ypgw_xz",ypgw_xz);
|
||||
comMap.put("djrq",djrq);
|
||||
comMap.put("xm",xm);
|
||||
comMap.put("xb",xb);
|
||||
comMap.put("xb_xz",xb_xz);
|
||||
comMap.put("csrq",csrq);
|
||||
comMap.put("mz",mz);
|
||||
comMap.put("mz_xz",mz_xz);
|
||||
comMap.put("jg",jg);
|
||||
comMap.put("jg_xz",jg_xz);
|
||||
comMap.put("hy",hy);
|
||||
comMap.put("hy_xz", hy_xz);
|
||||
comMap.put("zzmm",zzmm);
|
||||
comMap.put("zzmm_xz",zzmm_xz);
|
||||
comMap.put("sj",sj);
|
||||
comMap.put("yx",yx);
|
||||
comMap.put("pro",pro);
|
||||
comMap.put("city",city);
|
||||
comMap.put("qx",qx);
|
||||
comMap.put("xxdz",xxdz);
|
||||
comMap.put("xpro",xpro);
|
||||
comMap.put("xcity",xcity);
|
||||
comMap.put("xqx",xqx);
|
||||
comMap.put("xxxdz",xxxdz);
|
||||
comMap.put("jjlxr",jjlxr);
|
||||
comMap.put("jjlxrgx",jjlxrgx);
|
||||
comMap.put("lxrdh",lxrdh);
|
||||
comMap.put("english",english);
|
||||
comMap.put("cert",cert);
|
||||
comMap.put("eng_fj",eng_fj);
|
||||
comMap.put("qtyz",qtyz);
|
||||
comMap.put("djzs",djzs);
|
||||
comMap.put("qtyz_fj",qtyz_fj);
|
||||
comMap.put("zyzg",zyzg);
|
||||
comMap.put("zyzgzs",zyzgzs);
|
||||
comMap.put("zyzg_fj",zyzg_fj);
|
||||
comMap.put("qtjn",qtjn);
|
||||
comMap.put("bgrj",bgrj);
|
||||
comMap.put("qtjn_fj",qtjn_fj);
|
||||
comMap.put("xqah",xqah);
|
||||
comMap.put("gdxzsq",gdxzsq);
|
||||
comMap.put("qwxzsq",qwxzsq);
|
||||
comMap.put("sbyf",sbyf);
|
||||
comMap.put("sbnf",sbnf);
|
||||
comMap.put("gzlxdh",gzlxdh);
|
||||
comMap.put("zmr",zmr);
|
||||
comMap.put("zmrgw",zmrgw);
|
||||
comMap.put("sfjcldht",sfjcldht);
|
||||
comMap.put("sfjlcf",sfjlcf);
|
||||
comMap.put("sfjb",sfjb);
|
||||
comMap.put("sfss",sfss);
|
||||
comMap.put("sfyhjkgz",sfyhjkgz);
|
||||
comMap.put("sfyytj",sfyytj);
|
||||
comMap.put("sftgbszy",sftgbszy);
|
||||
comMap.put("tjrxm",tjrxm);
|
||||
comMap.put("tjrgx",tjrgx);
|
||||
comMap.put("bgsqs",bgsqs);
|
||||
comMap.put("gxr",gxr);
|
||||
comMap.put("gxrgx",gxrgx);
|
||||
comMap.put("sfty",sfty);
|
||||
comMap.put("tbr",tbr);
|
||||
}
|
||||
List<HashMap<String,String>> dt1_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt1 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt1------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt1_map = new HashMap<>();
|
||||
String xl = rs.getString("field008");
|
||||
String xl_xz = getSelectName(tableName,tableName+"_dt1","field008",xl);
|
||||
String start = rs.getString("field009");
|
||||
String end = rs.getString("field010");
|
||||
String xx = rs.getString("field004");
|
||||
String zy = rs.getString("field005");
|
||||
String xxxs = rs.getString("field011");
|
||||
String xxxs_xz = getSelectName(tableName,tableName+"_dt1","field011",xxxs);
|
||||
String xw = rs.getString("field012");
|
||||
String xw_xz = getSelectName(tableName,tableName+"_dt1","field012",xw);
|
||||
dt1_map.put("xl",xl);
|
||||
dt1_map.put("xl_xz",xl_xz);
|
||||
dt1_map.put("start",start);
|
||||
dt1_map.put("end",end);
|
||||
dt1_map.put("xx",xx);
|
||||
dt1_map.put("zy",zy);
|
||||
dt1_map.put("xxxs",xxxs);
|
||||
dt1_map.put("xxxs_xz",xxxs_xz);
|
||||
dt1_map.put("xw",xw);
|
||||
dt1_map.put("xw_xz",xw_xz);
|
||||
dt1_list.add(dt1_map);
|
||||
}
|
||||
writeLog("------sql dt1--data----"+dt1_list.toString());
|
||||
comMap.put("dt1",dt1_list);
|
||||
List<HashMap<String,String>> dt2_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt2 where mainid = '"+id+"'";
|
||||
rs.executeQuery(sql);
|
||||
writeLog("------sql dt2------"+sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt2_map = new HashMap<>();
|
||||
String start = rs.getString("field008");
|
||||
String end = rs.getString("field009");
|
||||
String gzdw = rs.getString("field003");
|
||||
String gzdwdz = rs.getString("field004");
|
||||
String gw = rs.getString("field005");
|
||||
String lzyy = rs.getString("field006");
|
||||
String lxdh = rs.getString("field007");
|
||||
dt2_map.put("start",start);
|
||||
dt2_map.put("end",end);
|
||||
dt2_map.put("gzdw",gzdw);
|
||||
dt2_map.put("gzdwdz",gzdwdz);
|
||||
dt2_map.put("gw",gw);
|
||||
dt2_map.put("lzyy",lzyy);
|
||||
dt2_map.put("lxdh",lxdh);
|
||||
dt2_list.add(dt2_map);
|
||||
}
|
||||
writeLog("------sql dt2--data----"+dt2_list.toString());
|
||||
comMap.put("dt2",dt2_list);
|
||||
List<HashMap<String,String>> dt3_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt3 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt3-----"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt3_map = new HashMap<>();
|
||||
String xm = rs.getString("field001");
|
||||
String gx = rs.getString("field005");
|
||||
String gx_xz = getSelectName(tableName,tableName+"_dt3","field005",gx);
|
||||
String nl = rs.getString("field003");
|
||||
String gzdw = rs.getString("field004");
|
||||
dt3_map.put("xm",xm);
|
||||
dt3_map.put("gx",gx);
|
||||
dt3_map.put("gx_xz",gx_xz);
|
||||
dt3_map.put("nl",nl);
|
||||
dt3_map.put("gzdw",gzdw);
|
||||
dt3_list.add(dt3_map);
|
||||
}
|
||||
writeLog("------sql dt3--data----"+dt3_list.toString());
|
||||
comMap.put("dt3",dt3_list);
|
||||
List<HashMap<String,String>> dt4_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt4 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt4------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt4_map = new HashMap<>();
|
||||
String yz = rs.getString("field001");
|
||||
String cert = rs.getString("field002");
|
||||
dt4_map.put("qtyz",yz);
|
||||
dt4_map.put("djzs",cert);
|
||||
dt4_list.add(dt4_map);
|
||||
}
|
||||
writeLog("------sql dt4--data----"+dt4_list.toString());
|
||||
comMap.put("dt4",dt4_list);
|
||||
List<HashMap<String,String>> dt5_list = new ArrayList<>();
|
||||
sql ="select * from "+tableName+"_dt5 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt5------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt5_map = new HashMap<>();
|
||||
String zgzs = rs.getString("field001");
|
||||
String bgrj = rs.getString("field002");
|
||||
dt5_map.put("zgzs",zgzs);
|
||||
dt5_map.put("bgrj",bgrj);
|
||||
dt5_list.add(dt5_map);
|
||||
}
|
||||
writeLog("------sql dt5--data----"+dt5_list.toString());
|
||||
comMap.put("dt5",dt5_list);
|
||||
|
||||
List<HashMap<String,String>> dt6_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt6 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt6------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt6_map = new HashMap<>();
|
||||
String wbk = rs.getString("field001");
|
||||
dt6_map.put("wbk",wbk);
|
||||
dt6_list.add(dt6_map);
|
||||
}
|
||||
writeLog("------sql dt6--data----"+dt6_list.toString());
|
||||
comMap.put("dt6",dt6_list);
|
||||
|
||||
List<HashMap<String,String>> dt7_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt7 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt7------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt7_map = new HashMap<>();
|
||||
String kcmc = rs.getString("field001");
|
||||
String ksrq = rs.getString("field002");
|
||||
String jsrq = rs.getString("field003");
|
||||
dt7_map.put("kcmc",kcmc);
|
||||
dt7_map.put("ksrq",ksrq);
|
||||
dt7_map.put("jsrq",jsrq);
|
||||
dt7_list.add(dt7_map);
|
||||
}
|
||||
writeLog("------sql dt7--data----"+dt7_list.toString());
|
||||
comMap.put("dt7",dt7_list);
|
||||
|
||||
List<HashMap<String,String>> dt8_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt8 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt8------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt8_map = new HashMap<>();
|
||||
String jlqk = rs.getString("field001");
|
||||
String jlqk_xz = getSelectName(tableName,tableName+"_dt8","field001",jlqk);
|
||||
String nr1 = rs.getString("field002");
|
||||
String nr2 = rs.getString("field003");
|
||||
dt8_map.put("jlqk",jlqk);
|
||||
dt8_map.put("jlqk_xz",jlqk_xz);
|
||||
dt8_map.put("nr1",nr1);
|
||||
dt8_map.put("nr2",nr2);
|
||||
dt8_list.add(dt8_map);
|
||||
}
|
||||
writeLog("------sql dt8--data----"+dt8_list.toString());
|
||||
comMap.put("dt8",dt8_list);
|
||||
|
||||
List<HashMap<String,String>> dt9_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt9 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt9------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt9_map = new HashMap<>();
|
||||
String rq = rs.getString("field001");
|
||||
String nr = rs.getString("field002");
|
||||
String yy = rs.getString("field003");
|
||||
String lb = rs.getString("field004");
|
||||
String jb = rs.getString("field005");
|
||||
String dw = rs.getString("field006");
|
||||
String je = rs.getString("field007");
|
||||
String bz = rs.getString("field008");
|
||||
dt9_map.put("rq",rq);
|
||||
dt9_map.put("nr",nr);
|
||||
dt9_map.put("yy",yy);
|
||||
dt9_map.put("lb",lb);
|
||||
dt9_map.put("jb",jb);
|
||||
dt9_map.put("dw",dw);
|
||||
dt9_map.put("je",je);
|
||||
dt9_map.put("bz",bz);
|
||||
dt9_list.add(dt9_map);
|
||||
}
|
||||
writeLog("------sql dt9--data----"+dt9_list.toString());
|
||||
comMap.put("dt9",dt9_list);
|
||||
|
||||
List<HashMap<String,String>> dt10_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt10 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt10------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt10_map = new HashMap<>();
|
||||
String rq = rs.getString("field001");
|
||||
String nr = rs.getString("field002");
|
||||
String yy = rs.getString("field003");
|
||||
String lb = rs.getString("field004");
|
||||
String jb = rs.getString("field005");
|
||||
String dw = rs.getString("field006");
|
||||
String je = rs.getString("field007");
|
||||
String bz = rs.getString("field008");
|
||||
dt10_map.put("rq",rq);
|
||||
dt10_map.put("nr",nr);
|
||||
dt10_map.put("yy",yy);
|
||||
dt10_map.put("lb",lb);
|
||||
dt10_map.put("jb",jb);
|
||||
dt10_map.put("dw",dw);
|
||||
dt10_map.put("je",je);
|
||||
dt10_map.put("bz",bz);
|
||||
dt10_list.add( dt10_map);
|
||||
}
|
||||
writeLog("------sql dt10--data----"+dt10_list.toString());
|
||||
comMap.put("dt10",dt10_list);
|
||||
|
||||
List<HashMap<String,String>> dt11_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt11 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt11------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt11_map = new HashMap<>();
|
||||
String rq = rs.getString("field001");
|
||||
String cg = rs.getString("field002");
|
||||
String jg = rs.getString("field003");
|
||||
String zl = rs.getString("field004");
|
||||
String bz = rs.getString("field005");
|
||||
|
||||
dt11_map.put("rq",rq);
|
||||
dt11_map.put("cg",cg);
|
||||
dt11_map.put("jg",jg);
|
||||
dt11_map.put("zl",zl);
|
||||
dt11_map.put("bz",bz);
|
||||
dt11_list.add( dt11_map);
|
||||
}
|
||||
writeLog("------sql dt11--data----"+dt11_list.toString());
|
||||
comMap.put("dt11",dt11_list);
|
||||
|
||||
List<HashMap<String,String>> dt12_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt12 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt12------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt12_map = new HashMap<>();
|
||||
String rq = rs.getString("field001");
|
||||
String tm = rs.getString("field002");
|
||||
String cbs = rs.getString("field003");
|
||||
String mt = rs.getString("field004");
|
||||
String bz = rs.getString("field005");
|
||||
|
||||
dt12_map.put("rq",rq);
|
||||
dt12_map.put("tm",tm);
|
||||
dt12_map.put("cbs",cbs);
|
||||
dt12_map.put("mt",mt);
|
||||
dt12_map.put("bz",bz);
|
||||
dt12_list.add( dt12_map);
|
||||
}
|
||||
writeLog("------sql dt12--data----"+dt12_list.toString());
|
||||
comMap.put("dt12",dt12_list);
|
||||
|
||||
List<HashMap<String,String>> dt13_list = new ArrayList<>();
|
||||
sql = "select * from "+tableName+"_dt13 where mainid = '"+id+"'";
|
||||
writeLog("------sql dt13------"+sql);
|
||||
rs.executeQuery(sql);
|
||||
while(rs.next()){
|
||||
HashMap<String,String> dt13_map = new HashMap<>();
|
||||
String ksrq = rs.getString("field001");
|
||||
String jsrq = rs.getString("field002");
|
||||
String mc = rs.getString("field003");
|
||||
String je = rs.getString("field004");
|
||||
String gj = rs.getString("field005");
|
||||
String gjly = rs.getString("field006");
|
||||
String zq = rs.getString("field007");
|
||||
String zw = rs.getString("field008");
|
||||
String bz = rs.getString("field009");
|
||||
|
||||
dt13_map.put("ksrq",ksrq);
|
||||
dt13_map.put("jsrq",jsrq);
|
||||
dt13_map.put("mc",mc);
|
||||
dt13_map.put("je",je);
|
||||
dt13_map.put("gj",gj);
|
||||
dt13_map.put("gjly",gjly);
|
||||
dt13_map.put("zq",zq);
|
||||
dt13_map.put("zw",zw);
|
||||
dt13_map.put("bz",bz);
|
||||
dt13_list.add( dt13_map);
|
||||
}
|
||||
writeLog("------sql dt12--data----"+dt13_list.toString());
|
||||
comMap.put("dt13",dt13_list);
|
||||
|
||||
writeLog("------sql data-----"+comMap.toString());
|
||||
apiResult.success(true,comMap,"success");
|
||||
}else {
|
||||
apiResult.fail("id_card为空");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
apiResult.fail("error");
|
||||
}
|
||||
return JSON.toJSONString(apiResult);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/updateAcc")
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String updateAcc(@Context HttpServletRequest request, @Context HttpServletResponse response){
|
||||
ApiResult<Boolean> apiResult = new ApiResult<>();
|
||||
RecordSet rs = new RecordSet();
|
||||
String billid = Util.null2String(request.getParameter("id"));
|
||||
String tableName = getFormId("datacenter_table");
|
||||
try {
|
||||
//------请在下面编写业务逻辑代码------
|
||||
String sql = "select * from "+tableName+" where id = '"+billid+"'";
|
||||
new BaseBean().writeLog("----datacenter---sql-:"+sql);
|
||||
rs.executeQuery(sql);
|
||||
if(rs.next()){
|
||||
String confirm = rs.getString("field051");
|
||||
new BaseBean().writeLog("----datacenter---confirm--:"+confirm);
|
||||
if(!confirm.equals("")){
|
||||
String eng_fj1 = rs.getString("field058");
|
||||
String qtyz_fj1 = rs.getString("field060");
|
||||
String zyzg_fj1 = rs.getString("field065");
|
||||
String qtjn_fj1 = rs.getString("field068");
|
||||
String eng_fj = rs.getString("field070");
|
||||
String qtyz_fj = rs.getString("field071");
|
||||
String zyzg_fj = rs.getString("field072");
|
||||
String qtjn_fj = rs.getString("field073");
|
||||
if(!eng_fj.equals("")){
|
||||
eng_fj1 += ","+eng_fj;
|
||||
}
|
||||
if(!qtyz_fj.equals("")){
|
||||
qtyz_fj1 += ","+qtyz_fj;
|
||||
}
|
||||
if(!zyzg_fj.equals("")){
|
||||
zyzg_fj1 += ","+zyzg_fj;
|
||||
}
|
||||
if(!qtjn_fj.equals("")){
|
||||
qtjn_fj1 += ","+qtjn_fj;
|
||||
}
|
||||
sql = "update "+tableName+" set field058=?,field060=?,field065=?,field068=? where id = '"+billid+"'";
|
||||
rs.executeUpdate(sql,eng_fj1,qtyz_fj1,zyzg_fj1,qtjn_fj1);
|
||||
}
|
||||
apiResult.success(true,true,"success");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
apiResult.fail("error");
|
||||
}
|
||||
return JSON.toJSONString(apiResult);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/updateData")
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String updateData(@Context HttpServletRequest request, @Context HttpServletResponse response){
|
||||
ApiResult<Boolean> apiResult = new ApiResult<>();
|
||||
RecordSet rs = new RecordSet();
|
||||
String billid = Util.null2String(request.getParameter("id"));
|
||||
String tableName = getFormId("datacenter_table");
|
||||
try {
|
||||
//------请在下面编写业务逻辑代码------
|
||||
String sql = "update "+tableName+" set field076 = '正式入职' where id = '"+billid+"'";
|
||||
new BaseBean().writeLog("----datacenter---sql-:"+sql);
|
||||
rs.executeQuery(sql);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
apiResult.fail("error");
|
||||
}
|
||||
return JSON.toJSONString(apiResult);
|
||||
}
|
||||
|
||||
public static String getFormId(String name){
|
||||
RecordSet recordSet = new RecordSet();
|
||||
String sql = "select cs from uf_xtpzb1 where xtbs ='"+name+"'";
|
||||
recordSet.execute(sql);
|
||||
if(recordSet.next()){
|
||||
return recordSet.getString("cs");
|
||||
}else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选择框的值
|
||||
* @param maintableName 主表表名
|
||||
* @param detailtableName 明细表表名
|
||||
* @param fieldName 字段名
|
||||
* @param selectValue 选择框值
|
||||
* @return 选择框名称
|
||||
*/
|
||||
public String getSelectName(String maintableName, String detailtableName, String fieldName, String selectValue){
|
||||
//writeLog("CSX--enter getSelectName");
|
||||
RecordSet rs0 = new RecordSet();
|
||||
String choiceBoxName = "";
|
||||
StringBuffer sql= new StringBuffer();
|
||||
sql.append("select t1.selectname \n");
|
||||
sql.append("from workflow_SelectItem t1\n");
|
||||
sql.append(", workflow_billfield t2\n");
|
||||
sql.append(", workflow_bill t3\n");
|
||||
sql.append(" where t1.fieldid=t2.id ");
|
||||
sql.append("and t2.billid=t3.id and t3.tablename='").append(maintableName).append("'");
|
||||
if(detailtableName==null){
|
||||
detailtableName=" ";
|
||||
//writeLog("detailtableName->"+detailtableName);
|
||||
}
|
||||
//writeLog("!StringUtils.isNotBlank(detailtableName)->"+!org.apache.commons.lang.StringUtils.isNotBlank(detailtableName));
|
||||
if(!com.alipay.oceanbase.jdbc.StringUtils.isNotBlank(detailtableName)){
|
||||
if(rs0.getDBType().equalsIgnoreCase("oracle")){//判断数据库类型是不是Oracle
|
||||
sql.append(" and t2.detailtable is null\n");
|
||||
}else{
|
||||
sql.append(" and t2.detailtable ='' \n");
|
||||
}
|
||||
}else{
|
||||
sql.append(" and t2.detailtable ='").append(detailtableName).append("' \n");
|
||||
}
|
||||
sql.append(" and t2.fieldname='").append(fieldName);
|
||||
sql.append("'\n and t1.selectvalue='").append(selectValue).append("'");
|
||||
//writeLog("getChoiceBoxNameSql->\n"+sql.toString());
|
||||
rs0.execute(sql.toString());
|
||||
if(rs0.next()){
|
||||
choiceBoxName = rs0.getString("selectname");
|
||||
}
|
||||
//writeLog("ChoiceBoxName->"+choiceBoxName);
|
||||
return choiceBoxName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.api.interfaces.liyi.common;
|
||||
|
||||
public class ApiResult<T> {
|
||||
|
||||
private boolean success;
|
||||
|
||||
private String message;
|
||||
|
||||
private T data;
|
||||
|
||||
public ApiResult() {
|
||||
}
|
||||
|
||||
public void success(boolean success, T data, String message) {
|
||||
this.success = success;
|
||||
this.data = data;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ApiResult<T> success(T data) {
|
||||
this.data = data;
|
||||
this.success = true;
|
||||
this.message = "";
|
||||
return this;
|
||||
}
|
||||
|
||||
public ApiResult<T> fail(String message) {
|
||||
this.message = message;
|
||||
this.success = false;
|
||||
this.data = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return this.success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,602 @@
|
|||
package com.api.interfaces.liyi.crod;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.api.interfaces.liyi.service.HuilianyiClientService;
|
||||
import com.api.interfaces.liyi.service.impl.HuilianyiClientServiceImpl;
|
||||
import com.engine.common.util.ServiceUtil;
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.formmode.exttools.impexp.common.DateUtils;
|
||||
import weaver.general.BaseBean;
|
||||
import weaver.general.TimeUtil;
|
||||
import weaver.general.Util;
|
||||
import weaver.interfaces.schedule.BaseCronJob;
|
||||
import weaver.soa.workflow.request.*;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
public class HuilianyiTravelJob extends BaseCronJob {
|
||||
private HuilianyiClientService getHuilianyiClientService(){
|
||||
return ServiceUtil.getService(HuilianyiClientServiceImpl.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
try {
|
||||
// RecordSet rs = new RecordSet();
|
||||
// RequestService service = new RequestService();
|
||||
// String nowdate = TimeUtil.getCurrentTimeString();
|
||||
String ccsq_wfid = getFormId("ccsq_wfid");
|
||||
String ccbg_wfid = getFormId("ccbg_wfid");
|
||||
String ccsqTable = getFormId("ccsq_tablename");
|
||||
String ccbgTable = getFormId("ccbg_tablename");
|
||||
//String query_time = getFormId("query_time");
|
||||
String currentDateTime = DateUtils.getCurrentDateTime();
|
||||
String[] s = currentDateTime.split(" ");
|
||||
String hour = s[1].split(":")[0];
|
||||
String startTime = "";
|
||||
// if(Integer.parseInt(hour)>0){
|
||||
// startTime = DateUtils.getCurrentDate() + " " + query_time;
|
||||
//
|
||||
// }else {
|
||||
// startTime = DateUtils.getCurrentDate()+ " 12:00:00";
|
||||
// }
|
||||
String cur_date = DateUtils.getCurrentDate();
|
||||
String cur_year = cur_date.split("-")[0];
|
||||
String cur_month = cur_date.split("-")[1];
|
||||
startTime = cur_year+"-"+cur_month+"-"+"01 00:00:00";
|
||||
//startTime = "2022-11-24 12:00:00";
|
||||
/**
|
||||
* 获取token
|
||||
*/
|
||||
String resp = getHuilianyiClientService().getToken();
|
||||
JSONObject res = JSONUtil.parseObj(resp);
|
||||
List<String> resp_list = new ArrayList<>();
|
||||
if(null != res.get("access_token")){
|
||||
new BaseBean().writeLog("------token----:"+res.getStr("access_token"));
|
||||
String token = res.getStr("access_token");
|
||||
/**
|
||||
* 获取数据
|
||||
*/
|
||||
HttpResponse response1 = getHuilianyiClientService().
|
||||
getTravelApplication(res.getStr("access_token"), startTime, currentDateTime, "1003,1012", "1", "100");
|
||||
resp = response1.body();
|
||||
String total = response1.header("X-Total-Count");
|
||||
new BaseBean().writeLog("------1st resp--"+resp);
|
||||
if(resp.equals("[]")){
|
||||
new BaseBean().writeLog("------no resp--");
|
||||
}
|
||||
else {
|
||||
resp_list.add(resp);
|
||||
}
|
||||
new BaseBean().writeLog("----total----"+total);
|
||||
int page = (Integer.parseInt(total)/100) + 1;
|
||||
if(page > 1){
|
||||
for(int i = 2;i <= page;i++){
|
||||
/**
|
||||
* 获取数据
|
||||
*/
|
||||
HttpResponse response2 = getHuilianyiClientService().
|
||||
getTravelApplication(res.getStr("access_token"),startTime,currentDateTime,"1003,1012",String.valueOf(i),"100");
|
||||
String resp2 = response2.body();
|
||||
new BaseBean().writeLog("------either resp--"+resp2);
|
||||
if(resp2.equals("[]")){
|
||||
new BaseBean().writeLog("------no resp--");
|
||||
}
|
||||
else {
|
||||
resp_list.add(resp2);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String result : resp_list) {
|
||||
JSONArray jsonArray = JSONUtil.parseArray(result);
|
||||
parseCreateReq(jsonArray,ccbg_wfid,ccsq_wfid,ccbgTable,ccsqTable,token);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装创建流程数据并创建流程
|
||||
* @param jsonArray
|
||||
* @param ccbg_wfid
|
||||
* @param ccsq_wfid
|
||||
* @param ccbgTable
|
||||
* @param ccsqTable
|
||||
*/
|
||||
private void parseCreateReq(JSONArray jsonArray, String ccbg_wfid, String ccsq_wfid, String ccbgTable, String ccsqTable,String token) {
|
||||
RecordSet rs = new RecordSet();
|
||||
RequestService service = new RequestService();
|
||||
String nowdate = TimeUtil.getCurrentTimeString();
|
||||
String tokenUrl = getFormId("hly_tokenUrl");
|
||||
jsonArray.stream().map(o -> (JSONObject) o).forEach(result -> {
|
||||
try {
|
||||
Set<String> comp_uid = new HashSet<>();
|
||||
List<String> emp_id = new ArrayList<>();
|
||||
String companions = "";
|
||||
JSONObject applicant = ((JSONObject) result).getJSONObject("applicant");
|
||||
String status = ((JSONObject) result).getStr("status");
|
||||
String employeeID =((JSONObject) applicant).getStr("employeeID");
|
||||
|
||||
String fullName = applicant.getStr("fullName");
|
||||
JSONArray custFormValues = ((JSONObject) result).getJSONArray("custFormValues");
|
||||
custFormValues.stream().map(o -> (JSONObject) o).forEach(data ->{
|
||||
String fieldName = ((JSONObject) data).getStr("fieldName");
|
||||
if(fieldName.equals("出差人员")){
|
||||
JSONArray comp_value = ((JSONObject) data).getJSONArray("value");
|
||||
comp_value.stream().map(o -> (JSONObject) o).forEach(comp ->{
|
||||
String userOID = ((JSONObject) comp).getStr("userOID");
|
||||
comp_uid.add(userOID);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if(comp_uid.size()>0){
|
||||
for (String uid : comp_uid) {
|
||||
HttpResponse user_res = HttpUtil.createGet(tokenUrl + "/api/open/user/"+uid)
|
||||
.header("Authorization", "Bearer ".concat(token))//头信息,多个头信息多次调用此方法即可
|
||||
.header("Content-Type", "application/json")
|
||||
.timeout(1000 * 120)
|
||||
.execute();
|
||||
String user_resp = user_res.body();
|
||||
//out.println("----user_resp:"+user_resp);
|
||||
JSONObject compInfo = JSONUtil.parseObj(user_resp);
|
||||
String empid = compInfo.getStr("employeeID");
|
||||
if(empid==null){
|
||||
}else {
|
||||
if(!emp_id.contains(empid)){
|
||||
emp_id.add(empid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(emp_id.size()>0){
|
||||
if(emp_id.size()>1){
|
||||
List<String> empids = emp_id;
|
||||
for (String txr_id : empids) {
|
||||
rs.executeQuery("select id from hrmresource where workcode = '"+txr_id+"'");
|
||||
while (rs.next()){
|
||||
if(companions.equals("")){
|
||||
companions = rs.getString("id");
|
||||
}else {
|
||||
companions += ","+rs.getString("id");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
String departmentNumber = ((JSONObject) result).getStr("departmentNumber");
|
||||
String version = ((JSONObject) result).getStr("version");
|
||||
String businessCode = ((JSONObject) result).getStr("businessCode");
|
||||
Boolean closed = ((JSONObject) result).getBool("closed");
|
||||
Boolean participantClosed = ((JSONObject) result).getBool("participantClosed");
|
||||
JSONObject travelApplication = ((JSONObject) result).getJSONObject("travelApplication");
|
||||
String startDate = travelApplication.getStr("startDate");
|
||||
startDate = startDate.replace("T", " ");
|
||||
startDate = startDate.replace("Z", "");
|
||||
//转时区
|
||||
startDate = convertDateGMT(startDate);
|
||||
String endDate = travelApplication.getStr("endDate");
|
||||
endDate = endDate.replace("T", " ");
|
||||
endDate = endDate.replace("Z", "");
|
||||
//转时区
|
||||
endDate = convertDateGMT(endDate);
|
||||
new BaseBean().writeLog("------result-1---:"+fullName+"---"+employeeID+"---txrids:"+companions+"---"+departmentNumber+"---"+version+"---"+businessCode+"---"+startDate+"---"+endDate+"---close---"+closed+"--partclose--"+participantClosed);
|
||||
String fromDate = "";
|
||||
String fromTime = "";
|
||||
String toDate = "";
|
||||
String toTime = "";
|
||||
//2022-11-17 09:00
|
||||
if(startDate!=null){
|
||||
fromDate = startDate.split(" ")[0];
|
||||
String time = startDate.split(" ")[1];
|
||||
fromTime = time.split(":")[0]+":"+time.split(":")[1];
|
||||
}
|
||||
if(endDate!=null){
|
||||
toDate = endDate.split(" ")[0];
|
||||
String time = endDate.split(" ")[1];
|
||||
toTime = time.split(":")[0]+":"+time.split(":")[1];
|
||||
}
|
||||
String reqName_sq = "";
|
||||
String reqName_bg = "";
|
||||
String workflowname = "";
|
||||
String req_sql = "";
|
||||
|
||||
String id = "";
|
||||
req_sql = "select id,departmentid from hrmresource where workcode = '"+employeeID+"'";
|
||||
rs.executeQuery(req_sql);
|
||||
if(rs.next()){
|
||||
id = rs.getString("id");
|
||||
departmentNumber = rs.getString("departmentid");
|
||||
}
|
||||
//出差 及 变更逻辑
|
||||
if(status.equals("1003")){
|
||||
if(Integer.parseInt(version)==0){
|
||||
req_sql = "select workflowname from workflow_base where id = '"+ccsq_wfid+"'";
|
||||
rs.executeQuery(req_sql);
|
||||
while (rs.next()){
|
||||
workflowname = rs.getString("workflowname");
|
||||
}
|
||||
reqName_sq = workflowname+"-"+fullName+"-"+ DateUtils.getCurrentDate();
|
||||
|
||||
Map<String, String> mainTable = new HashMap<>();
|
||||
mainTable.put("resourceId",id);
|
||||
mainTable.put("gh",employeeID);
|
||||
mainTable.put("departmentId",departmentNumber);
|
||||
mainTable.put("fromDate",fromDate);
|
||||
mainTable.put("fromTime",fromTime);
|
||||
mainTable.put("toDate",toDate);
|
||||
mainTable.put("toTime",toTime);
|
||||
mainTable.put("status","1003");
|
||||
mainTable.put("version",version);
|
||||
mainTable.put("sqdh",businessCode);
|
||||
mainTable.put("companion",companions);
|
||||
new BaseBean().writeLog("------data---:"+mainTable.toString());
|
||||
req_sql = "select count(id) as count from "+ccsqTable+" where sqdh = '"+businessCode+"' and version = 0";
|
||||
rs.executeQuery(req_sql);
|
||||
if(rs.next()){
|
||||
int count = rs.getInt("count");
|
||||
if(count==0){
|
||||
String reqId = creatRequest("1", ccsq_wfid, reqName_sq, false, mainTable, null);
|
||||
RequestInfo request = service.getRequest(Integer.valueOf(reqId));
|
||||
Boolean submit = service.nextNodeBySubmit(request, Integer.valueOf(reqId), 1, nowdate);
|
||||
if (submit) {
|
||||
new BaseBean().writeLog(reqId + "提交成功");
|
||||
} else {
|
||||
new BaseBean().writeLog(reqId + "流程提交异常");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if(Integer.parseInt(version)>=1){
|
||||
String changerequestid = "";
|
||||
String changetype = "";
|
||||
String ver = "1";
|
||||
String ccks_date = "";
|
||||
String ccks_time = "";
|
||||
String ccjs_date = "";
|
||||
String ccjs_time = "";
|
||||
String kqsc = "";
|
||||
String bgsc = "";
|
||||
String req_id = "";
|
||||
|
||||
/**
|
||||
* 版本大于1
|
||||
* 查出差 版本号倒序
|
||||
* 有出差,先变更撤销
|
||||
* 创建出差(条件是同一单号不同版本号)
|
||||
*/
|
||||
// req_sql = "select top 1 requestid,id,changetype,version from "+ccbgTable+" where sqdh = '"+businessCode+"' and changetype='1' order by version desc,id desc";
|
||||
// rs.executeQuery(req_sql);
|
||||
// if(rs.next()){
|
||||
// changerequestid = Util.null2String(rs.getString("requestid"));
|
||||
// changetype = rs.getString("changetype");
|
||||
// req_id = rs.getString("id");
|
||||
// ver = rs.getString("version");
|
||||
// }
|
||||
// //没有变更
|
||||
// if(changerequestid.equals("")){
|
||||
//先查出差
|
||||
req_sql = "select top 1 * from "+ccsqTable+" where sqdh = '"+businessCode+"' order by version desc ";
|
||||
rs.executeQuery(req_sql);
|
||||
if(rs.next()){
|
||||
ver = rs.getString("version");
|
||||
changerequestid = Util.null2String(rs.getString("requestid"));
|
||||
ccks_date = rs.getString("fromDate");
|
||||
ccks_time = rs.getString("fromTime");
|
||||
ccjs_date = rs.getString("toDate");
|
||||
ccjs_time = rs.getString("toTime");
|
||||
}
|
||||
//如果有 新建变更 撤销
|
||||
if(!changerequestid.equals("")){
|
||||
//只有 出差最大的版本比 获取的版本小 才需要变更撤销
|
||||
//如果第二天同样的数据进来 就不会重复撤销
|
||||
new BaseBean().writeLog("--new-:"+version+"---wf:"+ver);
|
||||
if(Integer.parseInt(ver) < Integer.parseInt(version)){
|
||||
req_sql = "select top 1 requestid,id,version from "+ccbgTable+" where sqdh = '"+businessCode+"' and changetype='1' and status = '1003' order by version desc ";
|
||||
rs.executeQuery(req_sql);
|
||||
String bgversion = "0";
|
||||
String bgreq = "";
|
||||
if(rs.next()){
|
||||
bgversion = rs.getString("version");
|
||||
bgreq = rs.getString("requestid");
|
||||
}
|
||||
if((!bgreq.equals("") && Integer.parseInt(bgversion)< Integer.parseInt(version)) || bgreq.equals("")){
|
||||
//如果未查到撤销对变更,但是有出差,先起变更撤销出差
|
||||
//获取流程名
|
||||
req_sql = "select workflowname from workflow_base where id = '"+ccbg_wfid+"'";
|
||||
rs.executeQuery(req_sql);
|
||||
while (rs.next()){
|
||||
workflowname = rs.getString("workflowname");
|
||||
}
|
||||
reqName_bg = workflowname+"-"+fullName+"-"+ DateUtils.getCurrentDate();
|
||||
Map<String, String> mainTable = new HashMap<>();
|
||||
mainTable.put("resourceId",id);
|
||||
mainTable.put("gh",employeeID);
|
||||
mainTable.put("status","1003");
|
||||
mainTable.put("version",version);
|
||||
mainTable.put("companion",companions);
|
||||
mainTable.put("changetype","1");
|
||||
mainTable.put("sqdh",businessCode);
|
||||
|
||||
mainTable.put("changerequestid",changerequestid);
|
||||
LinkedHashMap<String, List<Map<String, String>>> detail = new LinkedHashMap<>();
|
||||
List<Map<String, String>> list = new ArrayList<>();
|
||||
Map<String,String> map = new HashMap<>();
|
||||
map.put("detail_attendancefromDate",ccks_date);
|
||||
map.put("detail_attendancefromTime",ccks_time);
|
||||
map.put("detail_attendancetoDate",ccjs_date);
|
||||
map.put("detail_attendancetoTime",ccjs_time);
|
||||
//map.put("detail_attendanceduration",kqsc);
|
||||
map.put("detail_changefromDate",fromDate);
|
||||
map.put("detail_changefromTime",fromTime);
|
||||
map.put("detail_changetoDate",toDate);
|
||||
map.put("detail_changetoTime",toTime);
|
||||
//map.put("detail_changeduration",bgsc);
|
||||
list.add(map);
|
||||
detail.put("1",list);
|
||||
new BaseBean().writeLog("------data---:"+detail.toString());
|
||||
new BaseBean().writeLog("------create version---:"+version);
|
||||
if(!version.equals("0")){
|
||||
String reqId = creatRequest("1", ccbg_wfid, reqName_bg, false, mainTable, detail);
|
||||
RequestInfo request = service.getRequest(Integer.valueOf(reqId));
|
||||
Boolean submit = service.nextNodeBySubmit(request, Integer.valueOf(reqId), 1, nowdate);
|
||||
if (submit) {
|
||||
new BaseBean().writeLog(reqId + "提交成功");
|
||||
} else {
|
||||
|
||||
new BaseBean().writeLog(reqId + "流程提交异常");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
req_sql = "select count(id) as count from "+ccsqTable+" where sqdh = '"+businessCode+"' and version = '"+version+"'";
|
||||
rs.executeQuery(req_sql);
|
||||
if(rs.next()){
|
||||
int count = rs.getInt("count");
|
||||
if(count==0){
|
||||
req_sql = "select workflowname from workflow_base where id = '"+ccsq_wfid+"'";
|
||||
rs.executeQuery(req_sql);
|
||||
while (rs.next()){
|
||||
workflowname = rs.getString("workflowname");
|
||||
}
|
||||
reqName_sq = workflowname+"-"+fullName+"-"+ DateUtils.getCurrentDate();
|
||||
Map<String, String> mainTable = new HashMap<>();
|
||||
mainTable.put("resourceId",id);
|
||||
mainTable.put("gh",employeeID);
|
||||
mainTable.put("departmentId",departmentNumber);
|
||||
mainTable.put("fromDate",fromDate);
|
||||
mainTable.put("fromTime",fromTime);
|
||||
mainTable.put("toDate",toDate);
|
||||
mainTable.put("toTime",toTime);
|
||||
mainTable.put("status","1003");
|
||||
mainTable.put("version",version);
|
||||
mainTable.put("sqdh",businessCode);
|
||||
mainTable.put("companion",companions);
|
||||
new BaseBean().writeLog("------data---:"+mainTable.toString());
|
||||
String reqId = creatRequest("1", ccsq_wfid, reqName_sq, false, mainTable, null);
|
||||
RequestInfo request = service.getRequest(Integer.valueOf(reqId));
|
||||
Boolean submit = service.nextNodeBySubmit(request, Integer.valueOf(reqId), 1, nowdate);
|
||||
if (submit) {
|
||||
new BaseBean().writeLog(reqId + "提交成功");
|
||||
} else {
|
||||
new BaseBean().writeLog(reqId + "流程提交异常");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 出差作废逻辑
|
||||
else if(status.equals("1012")){
|
||||
Map<String, String> mainTable = new HashMap<>();
|
||||
mainTable.put("resourceId",id);
|
||||
mainTable.put("gh",employeeID);
|
||||
mainTable.put("status",status);
|
||||
mainTable.put("version",version);
|
||||
mainTable.put("changetype","1");
|
||||
mainTable.put("sqdh",businessCode);
|
||||
String changerequestid = "";
|
||||
String req_id = "" ;
|
||||
String changetype = "";
|
||||
String ccks_date = "";
|
||||
String ccks_time = "";
|
||||
String ccjs_date = "";
|
||||
String ccjs_time = "";
|
||||
String bgversion = "0";
|
||||
String ccversion = "0";
|
||||
req_sql = "select top 1 requestid,id,version from "+ccbgTable+" where sqdh = '"+businessCode+"' and changetype='1' and status = '1012' order by version desc ";
|
||||
rs.executeQuery(req_sql);
|
||||
if(rs.next()){
|
||||
changerequestid = Util.null2String(rs.getString("requestid"));
|
||||
}
|
||||
if(changerequestid.equals("")){
|
||||
req_sql = "select top 1 * from "+ccsqTable+" where sqdh = '"+businessCode+"' order by version desc";
|
||||
rs.executeQuery(req_sql);
|
||||
if(rs.next()){
|
||||
changerequestid = Util.null2String(rs.getString("requestid"));
|
||||
ccversion = rs.getString("version");
|
||||
ccks_date = rs.getString("fromDate");
|
||||
ccks_time = rs.getString("fromTime");
|
||||
ccjs_date = rs.getString("toDate");
|
||||
ccjs_time = rs.getString("toTime");
|
||||
}
|
||||
//获取流程名
|
||||
req_sql = "select workflowname from workflow_base where id = '"+ccbg_wfid+"'";
|
||||
rs.executeQuery(req_sql);
|
||||
while (rs.next()){
|
||||
workflowname = rs.getString("workflowname");
|
||||
}
|
||||
reqName_bg = workflowname+"-"+fullName+"-"+ DateUtils.getCurrentDate();
|
||||
mainTable.put("changerequestid",changerequestid);
|
||||
LinkedHashMap<String, List<Map<String, String>>> detail = new LinkedHashMap<>();
|
||||
List<Map<String, String>> list = new ArrayList<>();
|
||||
Map<String,String> map = new HashMap<>();
|
||||
map.put("detail_attendancefromDate",ccks_date);
|
||||
map.put("detail_attendancefromTime",ccks_time);
|
||||
map.put("detail_attendancetoDate",ccjs_date);
|
||||
map.put("detail_attendancetoTime",ccjs_time);
|
||||
//map.put("detail_attendanceduration",kqsc);
|
||||
map.put("detail_changefromDate",fromDate);
|
||||
map.put("detail_changefromTime",fromTime);
|
||||
map.put("detail_changetoDate",toDate);
|
||||
map.put("detail_changetoTime",toTime);
|
||||
//map.put("detail_changeduration",bgsc);
|
||||
list.add(map);
|
||||
detail.put("1",list);
|
||||
new BaseBean().writeLog("------data---:"+detail.toString());
|
||||
//if(!changerequestid.equals("") && Integer.parseInt(version)>Integer.parseInt(bgversion) && Integer.parseInt(version)>Integer.parseInt(ccversion)){
|
||||
if(!changerequestid.equals("")){
|
||||
String reqId = creatRequest("1", ccbg_wfid, reqName_bg, false, mainTable, detail);
|
||||
RequestInfo request = service.getRequest(Integer.valueOf(reqId));
|
||||
Boolean submit = service.nextNodeBySubmit(request, Integer.valueOf(reqId), 1, nowdate);
|
||||
if (submit) {
|
||||
new BaseBean().writeLog(reqId + "提交成功");
|
||||
} else {
|
||||
new BaseBean().writeLog(reqId + "流程提交异常");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建系统流程
|
||||
*
|
||||
* @param createrId 创建人id
|
||||
* @param workflowId 流程id
|
||||
* @param requestName 流程标题
|
||||
* @param isNextFlow 是否提交下一节点
|
||||
* @param mainTable 主表信息 Map key: 字段名 value: 值
|
||||
* @param detail 明细信息(必须LinkedHashMap) Map key:明细表序号 value: List {Map key: 字段名 value:
|
||||
* 值}
|
||||
* @return
|
||||
*/
|
||||
public String creatRequest(
|
||||
String createrId,
|
||||
String workflowId,
|
||||
String requestName,
|
||||
boolean isNextFlow,
|
||||
Map<String, String> mainTable,
|
||||
LinkedHashMap<String, List<Map<String, String>>> detail
|
||||
) throws Exception {
|
||||
|
||||
if (mainTable == null || "0".equals(createrId) || "0".equals(workflowId)) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
//请求基本信息
|
||||
RequestInfo requestInfo = new RequestInfo();
|
||||
requestInfo.setCreatorid(createrId); // 创建人
|
||||
requestInfo.setWorkflowid(workflowId); // 工作流id
|
||||
requestInfo.setDescription(requestName); // 标题
|
||||
|
||||
if (!isNextFlow) { // 是否提交下一节点
|
||||
requestInfo.setIsNextFlow("0");
|
||||
}
|
||||
|
||||
// 主表信息
|
||||
MainTableInfo mainTableInfo = new MainTableInfo();
|
||||
Property[] propertyArray = new Property[mainTable.size()];
|
||||
int p = 0;
|
||||
|
||||
for (Map.Entry<String, String> entry : mainTable.entrySet()) {
|
||||
propertyArray[p] = new Property();
|
||||
propertyArray[p].setName(entry.getKey());
|
||||
propertyArray[p].setValue(entry.getValue());
|
||||
p++;
|
||||
}
|
||||
mainTableInfo.setProperty(propertyArray);
|
||||
requestInfo.setMainTableInfo(mainTableInfo);
|
||||
|
||||
// 明细信息
|
||||
DetailTableInfo detailTableInfo = new DetailTableInfo();
|
||||
if (detail != null) {
|
||||
DetailTable[] detailTables = new DetailTable[detail.size()];
|
||||
int ds = 0;
|
||||
for (Map.Entry<String, List<Map<String, String>>> entry : detail.entrySet()) {
|
||||
DetailTable detailTable = new DetailTable();
|
||||
List<Map<String, String>> list = entry.getValue();
|
||||
for (Map<String, String> map : list) {
|
||||
Row row = new Row();
|
||||
for (Map.Entry<String, String> rentry : map.entrySet()) {
|
||||
Cell cell = new Cell();
|
||||
cell.setName("" + rentry.getKey());
|
||||
cell.setValue("" + rentry.getValue());
|
||||
row.addCell(cell);
|
||||
}
|
||||
detailTable.addRow(row);
|
||||
}
|
||||
detailTable.setId(entry.getKey());
|
||||
detailTables[ds] = detailTable;
|
||||
ds++;
|
||||
}
|
||||
detailTableInfo.setDetailTable(detailTables);
|
||||
requestInfo.setDetailTableInfo(detailTableInfo); // 明细表
|
||||
}
|
||||
RequestService service = new RequestService();
|
||||
String requestid = service.createRequest(requestInfo);
|
||||
// 创建请求id
|
||||
if(requestid == null){
|
||||
throw new RuntimeException("创建流程失败");
|
||||
}
|
||||
int requestidInt = Integer.valueOf(requestid);
|
||||
if(requestidInt < 0){
|
||||
throw new RuntimeException("创建流程失败");
|
||||
}
|
||||
return requestid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置表
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static String getFormId(String name){
|
||||
RecordSet recordSet = new RecordSet();
|
||||
String sql = "select cs from uf_xtpzb1 where xtbs ='"+name+"'";
|
||||
recordSet.execute(sql);
|
||||
if(recordSet.next()){
|
||||
return recordSet.getString("cs");
|
||||
}else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换时区
|
||||
* @param dateStr
|
||||
* @return
|
||||
* @throws ParseException
|
||||
*/
|
||||
public String convertDateGMT(String dateStr) throws ParseException {
|
||||
String sourceTimeZone = "GMT";
|
||||
String targetTimeZone = "GMT+8";
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
//获取传入的时间值
|
||||
Long time = new Date(sdf.parse(dateStr).getTime()).getTime();
|
||||
//获取源时区时间相对的GMT时间
|
||||
Long sourceRelativelyGMT = time - TimeZone.getTimeZone(sourceTimeZone).getRawOffset();
|
||||
//GMT时间+目标时间时区的偏移量获取目标时间
|
||||
Long targetTime = sourceRelativelyGMT + TimeZone.getTimeZone(targetTimeZone).getRawOffset();
|
||||
Date date = new Date(targetTime);
|
||||
return sdf.format(date);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.api.interfaces.liyi.service;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface HuilianyiClientService {
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
* @return
|
||||
*/
|
||||
String getToken();
|
||||
|
||||
/**
|
||||
* 增量差旅
|
||||
* @return
|
||||
*/
|
||||
HttpResponse getTravelApplication(String token, String startDate, String endDate, String status, String page, String size);
|
||||
|
||||
HttpResponse getCompInfo(String token, String uid);
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.api.interfaces.liyi.service.impl;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.api.interfaces.liyi.service.HuilianyiClientService;
|
||||
import com.engine.core.impl.Service;
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.general.BaseBean;
|
||||
import weaver.rsa.security.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class HuilianyiClientServiceImpl extends Service implements HuilianyiClientService {
|
||||
private static String clientId = "4b8b787c-40c1-4349-8217-5535a8327175";//需要替换
|
||||
private static String securet = "OTY4ZWJkZTQtOWRmZC00Y2QwLThmMTktNGQ3ZGFjNzUwMDI2";//需要替换
|
||||
private static String tokenUrl = "https://apistage.huilianyi.com/gateway";//需要替换
|
||||
|
||||
@Override
|
||||
public String getToken() {
|
||||
clientId = getFormId("hly_clientId");
|
||||
securet = getFormId("hly_securet");
|
||||
tokenUrl = getFormId("hly_tokenUrl");
|
||||
int MAX_TIME_OUT = 1000 * 120;
|
||||
String authStr = clientId.concat(":").concat(securet);
|
||||
String authStrEnc = new String(Base64.encodeBase64(authStr.getBytes()));
|
||||
String response = HttpUtil.createPost(tokenUrl+"/oauth/token?grant_type=client_credentials&scope=write")
|
||||
.header("Authorization", "Basic ".concat(authStrEnc))//头信息,多个头信息多次调用此方法即可
|
||||
.timeout(MAX_TIME_OUT)
|
||||
.execute().body();
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse getTravelApplication(String token, String startDate, String endDate, String status, String page, String size) {
|
||||
// String url = tokenUrl+"/api/open/travelApplication?access_token={AccessToken}&startDate={startDate}&endDate={endDate}&status={status}" +
|
||||
// "&page={page}&size={size}";
|
||||
int MAX_TIME_OUT = 1000 * 120;
|
||||
tokenUrl = getFormId("hly_tokenUrl");
|
||||
HttpResponse resp = HttpUtil.createGet(tokenUrl + "/api/open/travelApplication?access_token=" + token + "" +
|
||||
"&startDate=" + startDate + "&endDate=" + endDate + "&status=" + status + "&page=" + page + "&size=" + size + "")
|
||||
.header("Authorization", "Bearer ".concat(token))//头信息,多个头信息多次调用此方法即可
|
||||
.header("Content-Type", "application/json")
|
||||
.timeout(MAX_TIME_OUT)
|
||||
.execute();
|
||||
String response = resp.body();
|
||||
String total = resp.header("X-Total-Count");
|
||||
new BaseBean().writeLog("-- hly--resp---:"+response);
|
||||
Map<String,String> resMap = new HashMap<>();
|
||||
resMap.put("total",total);
|
||||
resMap.put("resp",response);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse getCompInfo(String token, String uid) {
|
||||
int MAX_TIME_OUT = 1000 * 120;
|
||||
HttpResponse user_res = HttpUtil.createGet(tokenUrl + "/api/open/user/"+uid)
|
||||
.header("Authorization", "Bearer ".concat(token))//头信息,多个头信息多次调用此方法即可
|
||||
.header("Content-Type", "application/json")
|
||||
.timeout(MAX_TIME_OUT)
|
||||
.execute();
|
||||
return user_res;
|
||||
}
|
||||
|
||||
public static String getFormId(String name){
|
||||
RecordSet recordSet = new RecordSet();
|
||||
String sql = "select cs from uf_xtpzb1 where xtbs ='"+name+"'";
|
||||
recordSet.execute(sql);
|
||||
if(recordSet.next()){
|
||||
return recordSet.getString("cs");
|
||||
}else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
package com.api.nonstandardext.zenner.job;
|
||||
|
||||
import com.api.nonstandardext.zenner.model.sap.PeriodBalance;
|
||||
import com.api.nonstandardext.zenner.utils.SAPWebserviceTool;
|
||||
import net.sf.json.JSONObject;
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.formmode.setup.ModeRightInfo;
|
||||
import weaver.general.BaseBean;
|
||||
import weaver.general.Util;
|
||||
import weaver.interfaces.schedule.BaseCronJob;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* 对账单同步
|
||||
*
|
||||
* 1. SAP数据
|
||||
*
|
||||
* 2.银行数据 银行当日几张余额 b2e0005(当日) b2e0012(历史)
|
||||
* 银行数据 银行收款单 b2e0035
|
||||
* 银行数据 银行付款单 b2e0035
|
||||
*
|
||||
* 3.OA 流程数据
|
||||
*/
|
||||
public class SyncAccountInfoFromSapJob extends BaseCronJob {
|
||||
|
||||
BaseBean logger = new BaseBean();
|
||||
|
||||
private final static String JobName = " SyncAccountInfoFromSapJob ";
|
||||
|
||||
private String interfaceName;
|
||||
|
||||
private String theNearPeriod;
|
||||
|
||||
private String comCodes; //6000
|
||||
private String sapAccount; //10020103
|
||||
|
||||
|
||||
public String getInterfaceName() {
|
||||
return interfaceName;
|
||||
}
|
||||
|
||||
public void setInterfaceName(String interfaceName) {
|
||||
this.interfaceName = interfaceName;
|
||||
}
|
||||
|
||||
public String getTheNearPeriod() {
|
||||
return theNearPeriod;
|
||||
}
|
||||
|
||||
public void setTheNearPeriod(String theNearPeriod) {
|
||||
this.theNearPeriod = theNearPeriod;
|
||||
}
|
||||
|
||||
public String getComCodes() {
|
||||
return comCodes;
|
||||
}
|
||||
|
||||
public void setComCodes(String comCodes) {
|
||||
this.comCodes = comCodes;
|
||||
}
|
||||
|
||||
public String getSapAccount() {
|
||||
return sapAccount;
|
||||
}
|
||||
|
||||
public void setSapAccount(String sapAccount) {
|
||||
this.sapAccount = sapAccount;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
logger.writeLog("-----" + JobName + " Begin------");
|
||||
|
||||
RecordSet rs = new RecordSet();
|
||||
try {
|
||||
logger.writeLog("-----" + JobName + " getInterfaceName------" + getInterfaceName());
|
||||
|
||||
// if (getInterfaceName().indexOf("syncGlaccPeriodBalancesFromSap") >= 0){
|
||||
|
||||
SAPWebserviceTool tool = new SAPWebserviceTool();
|
||||
String webserviceUrl = tool.getSystemParamValue("SAP_OA011_Webservice_URL");
|
||||
|
||||
Integer nearPeriod = Integer.parseInt(getTheNearPeriod());
|
||||
|
||||
String[] companyCodes = getComCodes().split(",");
|
||||
for (int c = 0; c < companyCodes.length; c++){
|
||||
if ("".equals(companyCodes[c])){
|
||||
continue;
|
||||
}
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
for (int i = 1; i <= nearPeriod; i++){
|
||||
syncGlaccPeriodBalancesFromSap(companyCodes[c], (cal.get(Calendar.MONTH) + 1) + "", cal.get(Calendar.YEAR) + "", getSapAccount(), tool);
|
||||
cal.add(Calendar.MONTH, -1);
|
||||
}
|
||||
}
|
||||
// }
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.writeLog(JobName + " 获取异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
logger.writeLog("--------------------" + JobName + " End---------------------------");
|
||||
}
|
||||
|
||||
public void syncGlaccPeriodBalancesFromSap(String comCode, String period, String year, String glAccount, SAPWebserviceTool tool) throws Exception {
|
||||
|
||||
String params = tool.callParams_011(comCode, period, year, glAccount);
|
||||
|
||||
JSONObject result = tool.callInterface_011(params);
|
||||
|
||||
logger.writeLog(JobName + " syncGlaccPeriodBalancesFromSap result : " + result);
|
||||
|
||||
JSONObject balanceResponse = result.getJSONObject("balanceResponse");
|
||||
PeriodBalance periodBalance = new PeriodBalance();
|
||||
periodBalance.setIvCompCode(comCode);
|
||||
periodBalance.setIvFiscYear(year);
|
||||
periodBalance.setIvFisPeriod(period);
|
||||
periodBalance.setEvBalance(Util.null2String(balanceResponse.getString("EvBalance")));
|
||||
periodBalance.setEvPerSales(Util.null2String(balanceResponse.getString("EvPerSales")));
|
||||
periodBalance.setEvCreditPer(Util.null2String(balanceResponse.getString("EvCreditPer")));
|
||||
periodBalance.setEvDebitsPer(Util.null2String(balanceResponse.getString("EvDebitsPer")));
|
||||
periodBalance.setEvCurrency(Util.null2String(balanceResponse.getString("EvCurrency")));
|
||||
periodBalance.setGlAccount(glAccount);
|
||||
|
||||
periodBalance.save(periodBalance, 52, "uf_period_balance");
|
||||
|
||||
// String result = "";
|
||||
//// String url = "http://127.0.0.1/uapws/service/nc65to63projectsysplugin";//这是接口地址,注意去掉.wsdl,否则会报错
|
||||
// Service service = new Service();
|
||||
// Call call = (Call) service.createCall();
|
||||
// call.setTargetEndpointAddress(webserviceUrl);
|
||||
// String parametersName = "string";//设置参数名
|
||||
// call.setOperationName("ZoaGlGetglaccperiodbalances");//设置方法名
|
||||
// call.addParameter("IvComCode", XMLType.XSD_STRING, ParameterMode.IN);//方法参数,1参数名、2参数类型、3.入参
|
||||
// call.addParameter("IvFisPeriod", XMLType.XSD_STRING, ParameterMode.IN);//方法参数,1参数名、2参数类型、3.入参
|
||||
// call.addParameter("IvFiscYear", XMLType.XSD_STRING, ParameterMode.IN);//方法参数,1参数名、2参数类型、3.入参
|
||||
// call.addParameter("IvGlAccount", XMLType.XSD_STRING, ParameterMode.IN);//方法参数,1参数名、2参数类型、3.入参
|
||||
// call.setReturnType(XMLType.XSD_STRING);//返回类型
|
||||
// JSONObject keyParams = new JSONObject();
|
||||
// keyParams.put("IvComCode", 6000);
|
||||
// keyParams.put("IvFisPeriod", 8);
|
||||
// keyParams.put("IvFiscYear", 2022);
|
||||
// keyParams.put("IvGlAccount", 12345);
|
||||
// String str = keyParams.toString();
|
||||
// logger.writeLog(JobName + " syncSapData Service Call str : " + str);
|
||||
// Object resultObject = call.invoke(new Object[] { 6000, 8, 2022, 12345 });//调用接口
|
||||
// result = (String) resultObject;
|
||||
}
|
||||
|
||||
public void setModeRight(int creater, int modeid, int sourceid) {
|
||||
ModeRightInfo moderightinfo = new ModeRightInfo();
|
||||
moderightinfo.setNewRight(true);
|
||||
moderightinfo.editModeDataShare(creater, modeid, sourceid);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
package com.api.nonstandardext.zenner.job;
|
||||
|
||||
import com.api.nonstandardext.zenner.model.bank.DayBalance;
|
||||
import com.api.nonstandardext.zenner.service.bank.Bank_b2e0005_Service;
|
||||
import com.api.nonstandardext.zenner.utils.ZennerApiService;
|
||||
import com.api.nonstandardext.zenner.utils.ZennerUtil;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.Element;
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.general.BaseBean;
|
||||
import weaver.general.Util;
|
||||
import weaver.interfaces.schedule.BaseCronJob;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 对账单同步
|
||||
*
|
||||
* 1.银行数据 银行当日几张余额 b2e0005(当日) b2e0012(历史)
|
||||
* 银行数据 银行收款单 b2e0035
|
||||
* 银行数据 银行付款单 b2e0035
|
||||
*
|
||||
* 2. SAP数据
|
||||
*
|
||||
* 3.OA 流程数据
|
||||
*/
|
||||
public class SyncAccountStatementJob extends BaseCronJob {
|
||||
|
||||
BaseBean logger = new BaseBean();
|
||||
|
||||
private String interfaceName;
|
||||
|
||||
private final static String JobName = " SyncAccountStatementJob ";
|
||||
|
||||
public String getInterfaceName() {
|
||||
return interfaceName;
|
||||
}
|
||||
|
||||
public void setInterfaceName(String interfaceName) {
|
||||
this.interfaceName = interfaceName;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
logger.writeLog("-----" + JobName + " Begin------");
|
||||
|
||||
RecordSet rs = new RecordSet();
|
||||
ZennerApiService zennerApiService = new ZennerApiService();
|
||||
try {
|
||||
logger.writeLog("-----" + JobName + " getInterfaceName------" + getInterfaceName());
|
||||
//银行
|
||||
String bankApiUrl = zennerApiService.getSystemConfigValue("BANK_API_URL");
|
||||
|
||||
String bankSql = "select * from uf_bank_account";
|
||||
rs.execute(bankSql);
|
||||
while (rs.next()){
|
||||
syncBank_b2e0005(bankApiUrl, Util.null2String(rs.getString("lxh")), Util.null2String(rs.getString("yxzh")));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.writeLog(JobName + " 获取异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
logger.writeLog("--------------------" + JobName + " End---------------------------");
|
||||
}
|
||||
|
||||
/**
|
||||
* 当日账号余额 b2e0005
|
||||
* @param bankApiUrl
|
||||
* @throws Exception
|
||||
*/
|
||||
public void syncBank_b2e0005(String bankApiUrl, String ibknum, String actacn) throws Exception {
|
||||
|
||||
String dirPath = "E:\\WEAVER\\bank\\";
|
||||
File dir = new File(dirPath);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
logger.writeLog(JobName + "..syncBank_b2e0005......,,,bankApiUrl: " + bankApiUrl);
|
||||
//当日账号余额
|
||||
Map<String, String> xmlParams = new HashMap<>();
|
||||
|
||||
xmlParams.put("termid", "E192168000104");
|
||||
xmlParams.put("trnid", "");
|
||||
xmlParams.put("cusopr", "395169759");
|
||||
xmlParams.put("custid", "387679060");
|
||||
xmlParams.put("trncod", "b2e0005");
|
||||
xmlParams.put("token", "");
|
||||
|
||||
xmlParams.put("ibknum", ibknum);
|
||||
xmlParams.put("actacn", actacn);
|
||||
String xmlFileUrl = dirPath + "b2e0005_" + ZennerUtil.parseToDateString(Calendar.getInstance().getTime(), ZennerUtil.formatYYYYMMDD)+ ".xml";
|
||||
logger.writeLog(JobName + ".syncBank_b2e0005.......,,,xmlFileUrl: " + xmlFileUrl);
|
||||
Bank_b2e0005_Service bankB2e0005Service = new Bank_b2e0005_Service();
|
||||
bankB2e0005Service.createXml(xmlFileUrl, xmlParams);
|
||||
|
||||
String apiParams = bankB2e0005Service.getXmlString(xmlFileUrl);
|
||||
|
||||
Integer pLen = apiParams.length();
|
||||
int ps = 500;
|
||||
int logPageNum = pLen / ps;
|
||||
int i = 0;
|
||||
if (pLen <= ps){
|
||||
logger.writeLog(JobName + ".syncBank_b2e0005.......,,,voucherParams last: " + apiParams);
|
||||
} else {
|
||||
for (i = 0; i < logPageNum; i++){
|
||||
logger.writeLog(JobName + ".syncBank_b2e0005.......,,,,,,voucherParams " + i + " : " + apiParams.substring(i * ps, (i + 1) * 500));
|
||||
}
|
||||
logger.writeLog(JobName + ".syncBank_b2e0005.......,,,voucherParams last: " + apiParams.substring((i-1) * 500));
|
||||
}
|
||||
|
||||
logger.writeLog(JobName + " bankApiUrl : " + bankApiUrl);
|
||||
|
||||
String result = ZennerUtil.httpPostToken(bankApiUrl, new HashMap<>(), apiParams);
|
||||
logger.writeLog(JobName + " syncBank_b2e0005 result : " + result);
|
||||
|
||||
Document doc = DocumentHelper.parseText(result); // 将xml转为dom对象
|
||||
Element root = doc.getRootElement(); // 获取根节点
|
||||
List<Element> elements = root.elements("trans");//获取名称为env:Body的子节点
|
||||
DayBalance dayBalance = new DayBalance();
|
||||
boolean statusOk = false;
|
||||
for (Object l2 : elements) { //遍历子元素
|
||||
|
||||
Element l2Element = (Element) l2;
|
||||
logger.writeLog("l2Element name :" + l2Element.getName());
|
||||
List<Element> elementsL3 = l2Element.elements();
|
||||
|
||||
for (Object l3 : elementsL3) { //遍历子元素
|
||||
|
||||
Element l3Element = (Element) l3;
|
||||
List<Element> elementsL4 = l3Element.elements();
|
||||
|
||||
for (Object l4 : elementsL4) { //遍历子元素
|
||||
|
||||
Element dataElement = (Element) l4;
|
||||
logger.writeLog("l4Element name :" + dataElement.getName());
|
||||
|
||||
if ("status".equals(dataElement.getName())){
|
||||
List<Element> elementsL5 = dataElement.elements();
|
||||
|
||||
for (Object l5 : elementsL5) { //遍历子元素
|
||||
Element l5Element = (Element) l5;
|
||||
if ("rspcod".equals(l5Element.getName())) {
|
||||
logger.writeLog("rspcod:" + l5Element.getStringValue());
|
||||
if (l5Element.getStringValue().equals("B001")){
|
||||
statusOk = true;
|
||||
} else {
|
||||
statusOk = false;
|
||||
}
|
||||
}
|
||||
if ("rspmsg".equals(l5Element.getName())) {
|
||||
logger.writeLog("rspmsg:" + l5Element.getStringValue());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.writeLog("statusOk:" + statusOk);
|
||||
if (statusOk){
|
||||
logger.writeLog("dataElement.getName():" + dataElement.getName());
|
||||
if ("b2e0005-rs".equals(dataElement.getName())){
|
||||
List<Element> elementsData = dataElement.elements();
|
||||
|
||||
for (Object data : elementsData) { //遍历子元素
|
||||
Element l4Element = (Element) data;
|
||||
if ("account".equals(l4Element.getName())){
|
||||
List<Element> elementsL5 = l4Element.elements();
|
||||
|
||||
for (Object l5 : elementsL5) { //遍历子元素
|
||||
Element l5Element = (Element) l5;
|
||||
if ("ibknum".equals(l5Element.getName())) {
|
||||
logger.writeLog("ibknum:" + l5Element.getStringValue());
|
||||
dayBalance.setIbknum(l5Element.getStringValue());
|
||||
}
|
||||
if ("actacn".equals(l5Element.getName())) {
|
||||
logger.writeLog("actacn:" + l5Element.getStringValue());
|
||||
dayBalance.setActacn(l5Element.getStringValue());
|
||||
}
|
||||
if ("curcde".equals(l5Element.getName())) {
|
||||
logger.writeLog("curcde:" + l5Element.getStringValue());
|
||||
dayBalance.setCurcde(l5Element.getStringValue());
|
||||
}
|
||||
if ("actname".equals(l5Element.getName())) {
|
||||
logger.writeLog("actname:" + l5Element.getStringValue());
|
||||
dayBalance.setActname(l5Element.getStringValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("balance".equals(l4Element.getName())) {
|
||||
List<Element> elementsL5 = l4Element.elements();
|
||||
|
||||
for (Object l5 : elementsL5) { //遍历子元素
|
||||
Element l5Element = (Element) l5;
|
||||
if ("bokbal".equals(l5Element.getName())) {
|
||||
logger.writeLog("bokbal:" + l5Element.getStringValue());
|
||||
dayBalance.setBokbal(l5Element.getStringValue());
|
||||
}
|
||||
if ("avabal".equals(l5Element.getName())) {
|
||||
logger.writeLog("avabal:" + l5Element.getStringValue());
|
||||
dayBalance.setAvabal(l5Element.getStringValue());
|
||||
}
|
||||
if ("currentavabal".equals(l5Element.getName())) {
|
||||
logger.writeLog("currentavabal:" + l5Element.getStringValue());
|
||||
if ("".equals(l5Element.getStringValue())){
|
||||
dayBalance.setCurrentavabal("0");
|
||||
} else {
|
||||
dayBalance.setCurrentavabal(l5Element.getStringValue());
|
||||
}
|
||||
|
||||
}
|
||||
if ("stpamt".equals(l5Element.getName())) {
|
||||
logger.writeLog("stpamt:" + l5Element.getStringValue());
|
||||
if ("".equals(l5Element.getStringValue())){
|
||||
dayBalance.setStpamt("0");
|
||||
} else {
|
||||
dayBalance.setStpamt(l5Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("ovramt".equals(l5Element.getName())) {
|
||||
logger.writeLog("ovramt:" + l5Element.getStringValue());
|
||||
dayBalance.setOvramt("".equals(l5Element.getStringValue()) ? "0" : l5Element.getStringValue());
|
||||
}
|
||||
if ("frzamt".equals(l5Element.getName())) {
|
||||
logger.writeLog("frzamt:" + l5Element.getStringValue());
|
||||
dayBalance.setFrzamt("".equals(l5Element.getStringValue()) ? "0" : l5Element.getStringValue());
|
||||
}
|
||||
if ("effauthamt".equals(l5Element.getName())) {
|
||||
logger.writeLog("effauthamt:" + l5Element.getStringValue());
|
||||
dayBalance.setEffauthamt("".equals(l5Element.getStringValue()) ? "0" : l5Element.getStringValue());
|
||||
}
|
||||
if ("effusdoverbal".equals(l5Element.getName())) {
|
||||
logger.writeLog("effusdoverbal:" + l5Element.getStringValue());
|
||||
dayBalance.setEffusdoverbal("".equals(l5Element.getStringValue()) ? "0" : l5Element.getStringValue());
|
||||
}
|
||||
if ("effuseablequota".equals(l5Element.getName())) {
|
||||
logger.writeLog("effuseablequota:" + l5Element.getStringValue());
|
||||
dayBalance.setEffuseablequota("".equals(l5Element.getStringValue()) ? "0" : l5Element.getStringValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("baldat".equals(l4Element.getName())) {
|
||||
logger.writeLog("baldat:" + l4Element.getStringValue());
|
||||
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
Date date = ZennerUtil.parseToDate(l4Element.getStringValue(), ZennerUtil.formatYYYYMMDD_NoSplit);
|
||||
dayBalance.setBaldat(ZennerUtil.parseToDateString(date, ZennerUtil.formatYYYYMMDD));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dayBalance.save(dayBalance, 50, "uf_bank_day_balance");
|
||||
logger.writeLog(JobName + " result dayBalance: " + dayBalance.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
package com.api.nonstandardext.zenner.job;
|
||||
|
||||
import com.api.nonstandardext.zenner.model.bank.TradeInfo;
|
||||
import com.api.nonstandardext.zenner.service.bank.Bank_b2e0035_Service;
|
||||
import com.api.nonstandardext.zenner.utils.ZennerApiService;
|
||||
import com.api.nonstandardext.zenner.utils.ZennerUtil;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.Element;
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.general.BaseBean;
|
||||
import weaver.general.Util;
|
||||
import weaver.interfaces.schedule.BaseCronJob;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 对账单同步
|
||||
*
|
||||
* 1.银行数据 银行当日几张余额 b2e0005(当日) b2e0012(历史)
|
||||
* 银行数据 银行收款单 b2e0035
|
||||
* 银行数据 银行付款单 b2e0035
|
||||
*
|
||||
* 2. SAP数据
|
||||
*
|
||||
* 3.OA 流程数据
|
||||
*/
|
||||
public class SyncAccountTradeInfoJob extends BaseCronJob {
|
||||
|
||||
BaseBean logger = new BaseBean();
|
||||
|
||||
private String interfaceName;
|
||||
|
||||
private final static String JobName = " SyncAccountTradeInfoJob ";
|
||||
|
||||
public String getInterfaceName() {
|
||||
return interfaceName;
|
||||
}
|
||||
|
||||
public void setInterfaceName(String interfaceName) {
|
||||
this.interfaceName = interfaceName;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
logger.writeLog("-----" + JobName + " Begin------");
|
||||
|
||||
RecordSet rs = new RecordSet();
|
||||
ZennerApiService zennerApiService = new ZennerApiService();
|
||||
try {
|
||||
logger.writeLog("-----" + JobName + " getInterfaceName------" + getInterfaceName());
|
||||
//银行
|
||||
String bankApiUrl = zennerApiService.getSystemConfigValue("BANK_API_URL");
|
||||
|
||||
String bankSql = "select * from uf_bank_account";
|
||||
rs.execute(bankSql);
|
||||
int pageSize = 50;
|
||||
while (rs.next()){
|
||||
int total = syncBank_b2e0035(bankApiUrl, Util.null2String(rs.getString("lxh")), Util.null2String(rs.getString("yxzh")), 1, pageSize);
|
||||
Integer totalPage = (total + pageSize - 1) / pageSize;
|
||||
logger.writeLog(JobName + " totalPage:" + totalPage);
|
||||
for (int pageNo = 2; pageNo <= totalPage; pageNo++) {
|
||||
int startNo = (pageNo - 1) * pageSize;
|
||||
int endNo = pageNo * pageSize;
|
||||
|
||||
logger.writeLog(JobName + " startNo:" + startNo + " endNo:" + endNo);
|
||||
int pageTotal = syncBank_b2e0035(bankApiUrl, Util.null2String(rs.getString("lxh")), Util.null2String(rs.getString("yxzh")), startNo, pageSize);
|
||||
logger.writeLog(JobName + " total:" + pageTotal);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.writeLog(JobName + " 获取异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
logger.writeLog("--------------------" + JobName + " End---------------------------");
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步收付款数据
|
||||
* @param bankApiUrl
|
||||
* @throws Exception
|
||||
*/
|
||||
public int syncBank_b2e0035(String bankApiUrl, String ibknum, String actacn, int start, int end) throws Exception {
|
||||
|
||||
int notenum = 0;
|
||||
String dirPath = "E:\\WEAVER\\bank\\";
|
||||
File dir = new File(dirPath);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
//当日账号余额
|
||||
Map<String, String> xmlParams = new HashMap<>();
|
||||
xmlParams.put("termid", "E192168000104");
|
||||
xmlParams.put("trnid", "");
|
||||
xmlParams.put("cusopr", "395169759");
|
||||
xmlParams.put("custid", "387679060");
|
||||
xmlParams.put("trncod", "b2e0035");
|
||||
xmlParams.put("token", "");
|
||||
|
||||
xmlParams.put("type", "2002");
|
||||
xmlParams.put("ibknum", ibknum);
|
||||
xmlParams.put("actacn", actacn);
|
||||
xmlParams.put("from", "20220919");
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.DAY_OF_MONTH, -1);
|
||||
xmlParams.put("to", ZennerUtil.parseToDateString(cal.getTime(), ZennerUtil.formatYYYYMMDD_NoSplit));
|
||||
xmlParams.put("amountFrom", "1");
|
||||
xmlParams.put("amountTo", "100000");
|
||||
xmlParams.put("begnum", start + "");
|
||||
xmlParams.put("recnum", end + "");
|
||||
xmlParams.put("direction", "0");
|
||||
|
||||
String xmlFileUrl = dirPath + "b2e0035_" + ZennerUtil.parseToDateString(Calendar.getInstance().getTime(), ZennerUtil.formatYYYYMMDD)+ ".xml";
|
||||
logger.writeLog(JobName + " xmlFileUrl : " + xmlFileUrl);
|
||||
Bank_b2e0035_Service bankB2e0035Service = new Bank_b2e0035_Service();
|
||||
bankB2e0035Service.createXml(xmlFileUrl, xmlParams);
|
||||
|
||||
String apiParams = bankB2e0035Service.getXmlString(xmlFileUrl);
|
||||
|
||||
Integer pLen = apiParams.length();
|
||||
int ps = 500;
|
||||
int logPageNum = pLen / ps;
|
||||
int i = 0;
|
||||
if (pLen <= ps){
|
||||
logger.writeLog(JobName + "........,,,voucherParams last: " + apiParams);
|
||||
} else {
|
||||
for (i = 0; i < logPageNum; i++){
|
||||
logger.writeLog(JobName + "........,,,,,,voucherParams " + i + " : " + apiParams.substring(i * ps, (i + 1) * 500));
|
||||
}
|
||||
logger.writeLog(JobName + "........,,,voucherParams last: " + apiParams.substring((i-1) * 500));
|
||||
}
|
||||
|
||||
logger.writeLog(JobName + " bankApiUrl : " + bankApiUrl);
|
||||
|
||||
String result = ZennerUtil.httpPostToken(bankApiUrl, new HashMap<>(), apiParams);
|
||||
|
||||
logger.writeLog(JobName + " syncBank_b2e0035 result : " + result);
|
||||
|
||||
Document doc = DocumentHelper.parseText(result); // 将xml转为dom对象
|
||||
Element root = doc.getRootElement(); // 获取根节点
|
||||
List<Element> elements = root.elements("trans");//获取名称为env:Body的子节点
|
||||
List<TradeInfo> tradeInfoList = new ArrayList<>();
|
||||
boolean statusOk = false;
|
||||
for (Object l2 : elements) { //遍历子元素
|
||||
|
||||
Element l2Element = (Element) l2;
|
||||
logger.writeLog(JobName + "l2Element name :" + l2Element.getName());
|
||||
List<Element> elementsL3 = l2Element.elements();
|
||||
|
||||
for (Object l3 : elementsL3) { //遍历子元素
|
||||
|
||||
Element l3Element = (Element) l3;
|
||||
List<Element> elementsL4 = l3Element.elements();
|
||||
|
||||
for (Object l4 : elementsL4) { //遍历子元素
|
||||
|
||||
Element dataElement = (Element) l4;
|
||||
logger.writeLog(JobName + "l4Element name :" + dataElement.getName());
|
||||
|
||||
if ("status".equals(dataElement.getName())){
|
||||
List<Element> elementsL5 = dataElement.elements();
|
||||
|
||||
for (Object l5 : elementsL5) { //遍历子元素
|
||||
Element l5Element = (Element) l5;
|
||||
if ("rspcod".equals(l5Element.getName())) {
|
||||
logger.writeLog("rspcod:" + l5Element.getStringValue());
|
||||
if (l5Element.getStringValue().equals("B001") || l5Element.getStringValue().equals("B002")){
|
||||
statusOk = true;
|
||||
} else {
|
||||
statusOk = false;
|
||||
}
|
||||
}
|
||||
if ("rspmsg".equals(l5Element.getName())) {
|
||||
logger.writeLog(JobName + "rspmsg:" + l5Element.getStringValue());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if ("totalnum".equals(dataElement.getName())){
|
||||
logger.writeLog("totalnum:" + dataElement.getStringValue());
|
||||
}
|
||||
if ("notenum".equals(dataElement.getName())){
|
||||
logger.writeLog("notenum:" + dataElement.getStringValue());
|
||||
String notenumStr = Util.null2String(dataElement.getStringValue());
|
||||
if ("".equals(notenum)){
|
||||
notenumStr = "0";
|
||||
}
|
||||
notenum = Integer.parseInt(notenumStr);
|
||||
}
|
||||
|
||||
logger.writeLog("statusOk:" + statusOk);
|
||||
if (statusOk){
|
||||
logger.writeLog(JobName + "dataElement.getName():" + dataElement.getName());
|
||||
if ("b2e0035-rs".equals(dataElement.getName())){
|
||||
|
||||
TradeInfo tradeInfo = new TradeInfo();
|
||||
|
||||
List<Element> elementsData = dataElement.elements();
|
||||
|
||||
for (Object data : elementsData) { //遍历子元素
|
||||
Element l4Element = (Element) data;
|
||||
if ("fractn".equals(l4Element.getName())){
|
||||
List<Element> elementsL5 = l4Element.elements();
|
||||
|
||||
for (Object l5 : elementsL5) { //遍历子元素
|
||||
Element l5Element = (Element) l5;
|
||||
if ("ibknum".equals(l5Element.getName())) {
|
||||
tradeInfo.setIbknum(l5Element.getStringValue());
|
||||
}
|
||||
if ("actacn".equals(l5Element.getName())) {
|
||||
tradeInfo.setActacn(l5Element.getStringValue());
|
||||
}
|
||||
if ("acntname".equals(l5Element.getName())) {
|
||||
tradeInfo.setAcntname(l5Element.getStringValue());
|
||||
}
|
||||
if ("ibkname".equals(l5Element.getName())) {
|
||||
tradeInfo.setIbkname(l5Element.getStringValue());
|
||||
}
|
||||
if ("outref".equals(l5Element.getName())) {
|
||||
tradeInfo.setOutref(l5Element.getStringValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("toactn".equals(l4Element.getName())) {
|
||||
List<Element> elementsL5 = l4Element.elements();
|
||||
|
||||
for (Object l5 : elementsL5) { //遍历子元素
|
||||
Element l5Element = (Element) l5;
|
||||
if ("toibkn".equals(l5Element.getName())) {
|
||||
logger.writeLog(JobName + "toibkn:" + l5Element.getStringValue());
|
||||
tradeInfo.setToibkn(l5Element.getStringValue());
|
||||
}
|
||||
if ("actacn".equals(l5Element.getName())) {
|
||||
logger.writeLog(JobName + "actacn:" + l5Element.getStringValue());
|
||||
tradeInfo.setActacn_receipt(l5Element.getStringValue());
|
||||
}
|
||||
if ("toname".equals(l5Element.getName())) {
|
||||
logger.writeLog(JobName + "toname:" + l5Element.getStringValue());
|
||||
tradeInfo.setToname(l5Element.getStringValue());
|
||||
}
|
||||
if ("tobank".equals(l5Element.getName())) {
|
||||
logger.writeLog(JobName + "tobank:" + l5Element.getStringValue());
|
||||
tradeInfo.setTobank(l5Element.getStringValue());
|
||||
}
|
||||
if ("tobref".equals(l5Element.getName())) {
|
||||
logger.writeLog(JobName + "tobref:" + l5Element.getStringValue());
|
||||
tradeInfo.setTobref(l5Element.getStringValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("txndate".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
Date date = ZennerUtil.parseToDate(l4Element.getStringValue(), ZennerUtil.formatYYYYMMDD_NoSplit);
|
||||
tradeInfo.setTxndate_time(ZennerUtil.parseToDateString(date, ZennerUtil.formatYYYYMMDD));
|
||||
}
|
||||
}
|
||||
if ("txnamt".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setTxnamt(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("acctbal".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setAcctbal(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("avlbal".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setAvlbal(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("frzamt".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setFrzamt(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("overdramt".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setOverdramt(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("avloverdramt".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setAvloverdramt(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("useinfo".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setUseinfo(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("furinfo".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setFy(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("transtype".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setTranstype(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("trncur".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setTrncur(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
if ("direction".equals(l4Element.getName())) {
|
||||
if (!"".equals(l4Element.getStringValue())){
|
||||
tradeInfo.setDirection(l4Element.getStringValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tradeInfoList.add(tradeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.writeLog(JobName + " result tradeInfoList size: " + tradeInfoList.size());
|
||||
for (TradeInfo tradeInfo : tradeInfoList){
|
||||
if (!"".equals(tradeInfo.getIbknum())){
|
||||
tradeInfo.save(tradeInfo, 51, "uf_bank_trade_info");
|
||||
}
|
||||
}
|
||||
|
||||
return notenum;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,379 @@
|
|||
package com.api.nonstandardext.zenner.model.bank;
|
||||
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.formmode.setup.ModeRightInfo;
|
||||
import weaver.general.BaseBean;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 当日余额
|
||||
*/
|
||||
public class DayBalance extends BaseBean {
|
||||
|
||||
private Integer formmodeid;
|
||||
private String modedatacreater;
|
||||
private String modedatacreatertype;
|
||||
private String modedatacreatedate;
|
||||
private String modedatacreatetime;
|
||||
|
||||
//联行号
|
||||
private String ibknum;
|
||||
|
||||
//账号
|
||||
private String actacn;
|
||||
|
||||
//货币码
|
||||
private String curcde;
|
||||
|
||||
//账户户名
|
||||
private String actname;
|
||||
|
||||
//账面余额
|
||||
private String bokbal;
|
||||
|
||||
//有效余额
|
||||
private String avabal;
|
||||
|
||||
//一户通主账户活期账户余额
|
||||
private String currentavabal;
|
||||
|
||||
//圈存金额
|
||||
private String stpamt;
|
||||
|
||||
//透支额度
|
||||
private String ovramt;
|
||||
|
||||
//冻结余额
|
||||
private String frzamt;
|
||||
|
||||
//有效额度
|
||||
private String effauthamt;
|
||||
|
||||
//有效已用额度
|
||||
private String effusdoverbal;
|
||||
|
||||
//有效未用额度
|
||||
private String effuseablequota;
|
||||
|
||||
//系统日期
|
||||
private String baldat;
|
||||
|
||||
public Integer save(DayBalance ufModel, Integer formmodeid, String tableName) {
|
||||
|
||||
String modelName = "银行当日余额";
|
||||
|
||||
Integer billId = 0;
|
||||
|
||||
try {
|
||||
RecordSet rs = new RecordSet();
|
||||
String fieldSql = "";
|
||||
String valueSql = "";
|
||||
boolean result = false;
|
||||
String currentDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
ufModel.setFormmodeid(formmodeid);
|
||||
ufModel.setModedatacreater("1");
|
||||
ufModel.setModedatacreatertype("0");
|
||||
ufModel.setModedatacreatedate(currentDateTime.substring(0, 10));
|
||||
ufModel.setModedatacreatetime(currentDateTime.substring(11));
|
||||
|
||||
String existSql = "select id from " + tableName + " where ibknum='" + ufModel.getIbknum() + "' and actacn='" + ufModel.getActacn() + "' and curcde='" + ufModel.getCurcde() + "' and baldat='" + ufModel.getBaldat() + "'";
|
||||
rs.execute(existSql);
|
||||
if (rs.next()) {
|
||||
billId = rs.getInt("id");
|
||||
String msg = update(modelName, tableName, ufModel);
|
||||
if (!"".equals(msg)){
|
||||
this.writeLog(modelName + ", 保存异常: " + msg);
|
||||
}
|
||||
return billId;
|
||||
}
|
||||
|
||||
// 获取实体类的所有属性,返回Field数组
|
||||
Field[] field = ufModel.getClass().getDeclaredFields();
|
||||
// 遍历所有属性
|
||||
for (int i = 0; i < field.length; i++) {
|
||||
// 获取属性的名字,并将属性第一个字符大写
|
||||
String name = field[i].getName();
|
||||
name = name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
// 得到属性类型
|
||||
String type = field[i].getGenericType().toString();
|
||||
if (type.equals("class java.lang.String")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
String value = (String) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
fieldSql += "," + name;
|
||||
valueSql += ",'" + value.trim() + "'";
|
||||
}
|
||||
}
|
||||
if (type.equals("class java.lang.Integer")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
Integer value = (Integer) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
fieldSql += "," + name;
|
||||
valueSql += "," + value + "";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!"".equals(fieldSql)) {
|
||||
fieldSql = fieldSql.substring(1);
|
||||
valueSql = valueSql.substring(1);
|
||||
String insertSql = "insert into " + tableName + " (" + fieldSql + ") values (" + valueSql + ")";
|
||||
result = rs.execute(insertSql);
|
||||
if (!result) {
|
||||
return -1;
|
||||
}
|
||||
RecordSet rightRs = new RecordSet();
|
||||
writeLog(modelName + ", insertSql ->" + insertSql + ", result:" + result + ", formmodeid: " + formmodeid);
|
||||
rightRs.execute("SELECT id FROM " + tableName + " where ibknum='" + ufModel.getIbknum() + "' and actacn='" + ufModel.getActacn() + "' and curcde='" + ufModel.getCurcde() + "' and baldat='" + ufModel.getBaldat() + "'");
|
||||
if (rightRs.next()) {
|
||||
billId = rightRs.getInt("id");
|
||||
this.setModeRight(1, formmodeid, billId);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
writeLog(modelName + ", 新增报错 ->" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
return billId;
|
||||
}
|
||||
|
||||
public String update(String modelName, String tableName, DayBalance ufModel) throws Exception{
|
||||
writeLog(modelName + ", update -> formmodeid: " + formmodeid);
|
||||
RecordSet rs = new RecordSet();
|
||||
String setSql = "";
|
||||
boolean result = false;
|
||||
|
||||
try {
|
||||
// 获取实体类的所有属性,返回Field数组
|
||||
Field[] field = ufModel.getClass().getDeclaredFields();
|
||||
// 遍历所有属性
|
||||
for(int i = 0; i < field.length; i++) {
|
||||
// 获取属性的名字,并将属性第一个字符大写
|
||||
String name = field[i].getName();
|
||||
name = name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
// 主键不更新
|
||||
if("Ibknum".equals(name) || "Actacn".equals(name) || "Curcde".equals(name) || "Baldat".equals(name) || "Modedatacreatedate".equals(name) || "Modedatacreatetime".equals(name)) {
|
||||
continue;
|
||||
}
|
||||
// 得到属性类型
|
||||
String type = field[i].getGenericType().toString();
|
||||
if (type.equals("class java.lang.String")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
String value = (String) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
setSql += "," + name + "='" + value + "'";
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals("class java.lang.Integer")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
Integer value = (Integer) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
setSql += "," + name + "=" + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!"".equals(setSql)) {
|
||||
setSql = setSql.substring(1);
|
||||
String updateSql = "update " + tableName + " set " + setSql + " where ibknum='" + ufModel.getIbknum() + "' and actacn='" + ufModel.getActacn() + "' and curcde='" + ufModel.getCurcde() + "' and baldat='" + ufModel.getBaldat() + "'";
|
||||
writeLog(modelName + ", updateSql ->" + updateSql);
|
||||
result = rs.execute(updateSql);
|
||||
if (!result){
|
||||
return "修改失败";
|
||||
}
|
||||
}
|
||||
} catch (Exception e){
|
||||
writeLog(modelName + ", 修改报错 ->" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return e.getMessage();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public void setModeRight(int creater, int modeid, int sourceid) {
|
||||
ModeRightInfo moderightinfo = new ModeRightInfo();
|
||||
moderightinfo.setNewRight(true);
|
||||
moderightinfo.editModeDataShare(creater, modeid, sourceid);
|
||||
}
|
||||
|
||||
|
||||
public Integer getFormmodeid() {
|
||||
return formmodeid;
|
||||
}
|
||||
|
||||
public void setFormmodeid(Integer formmodeid) {
|
||||
this.formmodeid = formmodeid;
|
||||
}
|
||||
|
||||
public String getModedatacreater() {
|
||||
return modedatacreater;
|
||||
}
|
||||
|
||||
public void setModedatacreater(String modedatacreater) {
|
||||
this.modedatacreater = modedatacreater;
|
||||
}
|
||||
|
||||
public String getModedatacreatertype() {
|
||||
return modedatacreatertype;
|
||||
}
|
||||
|
||||
public void setModedatacreatertype(String modedatacreatertype) {
|
||||
this.modedatacreatertype = modedatacreatertype;
|
||||
}
|
||||
|
||||
public String getModedatacreatedate() {
|
||||
return modedatacreatedate;
|
||||
}
|
||||
|
||||
public void setModedatacreatedate(String modedatacreatedate) {
|
||||
this.modedatacreatedate = modedatacreatedate;
|
||||
}
|
||||
|
||||
public String getModedatacreatetime() {
|
||||
return modedatacreatetime;
|
||||
}
|
||||
|
||||
public void setModedatacreatetime(String modedatacreatetime) {
|
||||
this.modedatacreatetime = modedatacreatetime;
|
||||
}
|
||||
|
||||
public String getIbknum() {
|
||||
return ibknum;
|
||||
}
|
||||
|
||||
public void setIbknum(String ibknum) {
|
||||
this.ibknum = ibknum;
|
||||
}
|
||||
|
||||
public String getActacn() {
|
||||
return actacn;
|
||||
}
|
||||
|
||||
public void setActacn(String actacn) {
|
||||
this.actacn = actacn;
|
||||
}
|
||||
|
||||
public String getCurcde() {
|
||||
return curcde;
|
||||
}
|
||||
|
||||
public void setCurcde(String curcde) {
|
||||
this.curcde = curcde;
|
||||
}
|
||||
|
||||
public String getActname() {
|
||||
return actname;
|
||||
}
|
||||
|
||||
public void setActname(String actname) {
|
||||
this.actname = actname;
|
||||
}
|
||||
|
||||
public String getBokbal() {
|
||||
return bokbal;
|
||||
}
|
||||
|
||||
public void setBokbal(String bokbal) {
|
||||
this.bokbal = bokbal;
|
||||
}
|
||||
|
||||
public String getAvabal() {
|
||||
return avabal;
|
||||
}
|
||||
|
||||
public void setAvabal(String avabal) {
|
||||
this.avabal = avabal;
|
||||
}
|
||||
|
||||
public String getCurrentavabal() {
|
||||
return currentavabal;
|
||||
}
|
||||
|
||||
public void setCurrentavabal(String currentavabal) {
|
||||
this.currentavabal = currentavabal;
|
||||
}
|
||||
|
||||
public String getStpamt() {
|
||||
return stpamt;
|
||||
}
|
||||
|
||||
public void setStpamt(String stpamt) {
|
||||
this.stpamt = stpamt;
|
||||
}
|
||||
|
||||
public String getOvramt() {
|
||||
return ovramt;
|
||||
}
|
||||
|
||||
public void setOvramt(String ovramt) {
|
||||
this.ovramt = ovramt;
|
||||
}
|
||||
|
||||
public String getFrzamt() {
|
||||
return frzamt;
|
||||
}
|
||||
|
||||
public void setFrzamt(String frzamt) {
|
||||
this.frzamt = frzamt;
|
||||
}
|
||||
|
||||
public String getEffauthamt() {
|
||||
return effauthamt;
|
||||
}
|
||||
|
||||
public void setEffauthamt(String effauthamt) {
|
||||
this.effauthamt = effauthamt;
|
||||
}
|
||||
|
||||
public String getEffusdoverbal() {
|
||||
return effusdoverbal;
|
||||
}
|
||||
|
||||
public void setEffusdoverbal(String effusdoverbal) {
|
||||
this.effusdoverbal = effusdoverbal;
|
||||
}
|
||||
|
||||
public String getEffuseablequota() {
|
||||
return effuseablequota;
|
||||
}
|
||||
|
||||
public void setEffuseablequota(String effuseablequota) {
|
||||
this.effuseablequota = effuseablequota;
|
||||
}
|
||||
|
||||
public String getBaldat() {
|
||||
return baldat;
|
||||
}
|
||||
|
||||
public void setBaldat(String baldat) {
|
||||
this.baldat = baldat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DayBalance{" +
|
||||
"ibknum='" + ibknum + '\'' +
|
||||
", actacn='" + actacn + '\'' +
|
||||
", curcde='" + curcde + '\'' +
|
||||
", actname='" + actname + '\'' +
|
||||
", bokbal='" + bokbal + '\'' +
|
||||
", avabal='" + avabal + '\'' +
|
||||
", currentavabal='" + currentavabal + '\'' +
|
||||
", stpamt='" + stpamt + '\'' +
|
||||
", ovramt='" + ovramt + '\'' +
|
||||
", frzamt='" + frzamt + '\'' +
|
||||
", effauthamt='" + effauthamt + '\'' +
|
||||
", effusdoverbal='" + effusdoverbal + '\'' +
|
||||
", effuseablequota='" + effuseablequota + '\'' +
|
||||
", baldat='" + baldat + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,582 @@
|
|||
package com.api.nonstandardext.zenner.model.bank;
|
||||
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.formmode.setup.ModeRightInfo;
|
||||
import weaver.general.BaseBean;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 当日余额
|
||||
*/
|
||||
public class TradeInfo extends BaseBean {
|
||||
|
||||
private Integer formmodeid;
|
||||
private String modedatacreater;
|
||||
private String modedatacreatertype;
|
||||
private String modedatacreatedate;
|
||||
private String modedatacreatetime;
|
||||
|
||||
//付款行号
|
||||
private String ibknum;
|
||||
|
||||
//付款账号
|
||||
private String actacn;
|
||||
|
||||
//货币码
|
||||
private String curcde;
|
||||
|
||||
//账户户名
|
||||
private String actname;
|
||||
|
||||
//付款人
|
||||
private String acntname;
|
||||
|
||||
//付款人开户行名
|
||||
private String ibkname;
|
||||
|
||||
//汇款行业务编号
|
||||
private String outref;
|
||||
|
||||
//收款行号
|
||||
private String toibkn;
|
||||
|
||||
//收款账号
|
||||
private String actacn_receipt;
|
||||
|
||||
//收款行业务编号
|
||||
private String tobref;
|
||||
|
||||
//收款人
|
||||
private String toname;
|
||||
|
||||
//被代理行号
|
||||
private String mactibkn;
|
||||
|
||||
//被代理账号
|
||||
private String mactacn;
|
||||
|
||||
//被代理账户名
|
||||
private String mactname;
|
||||
|
||||
//被代理账户开户行名
|
||||
private String mactbank;
|
||||
|
||||
//凭证号或传票号
|
||||
private String vchnum;
|
||||
|
||||
//记录标识号
|
||||
private String transid;
|
||||
|
||||
//客户业务编号后12位
|
||||
private String insid;
|
||||
|
||||
//交易时间
|
||||
private String txndate_time;
|
||||
|
||||
//金额
|
||||
private String txnamt;
|
||||
|
||||
//交易后余额
|
||||
private String acctbal;
|
||||
|
||||
//可用余额
|
||||
private String avlbal;
|
||||
|
||||
//冻结金额
|
||||
private String frzamt;
|
||||
|
||||
//透支额度
|
||||
private String overdramt;
|
||||
|
||||
//可用透支额度
|
||||
private String avloverdramt;
|
||||
|
||||
//用途
|
||||
private String useinfo;
|
||||
|
||||
//附言
|
||||
private String fy;
|
||||
|
||||
//业务类型
|
||||
private String transtype;
|
||||
|
||||
//货币名称
|
||||
private String trncur;
|
||||
|
||||
//来往账标识
|
||||
private String direction;
|
||||
|
||||
//收款人开户行名
|
||||
private String tobank;
|
||||
|
||||
public Integer save(TradeInfo ufModel, Integer formmodeid, String tableName) {
|
||||
|
||||
String modelName = "银行交易信息";
|
||||
|
||||
Integer billId = 0;
|
||||
|
||||
try {
|
||||
RecordSet rs = new RecordSet();
|
||||
String fieldSql = "";
|
||||
String valueSql = "";
|
||||
boolean result = false;
|
||||
String currentDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
ufModel.setFormmodeid(formmodeid);
|
||||
ufModel.setModedatacreater("1");
|
||||
ufModel.setModedatacreatertype("0");
|
||||
ufModel.setModedatacreatedate(currentDateTime.substring(0, 10));
|
||||
ufModel.setModedatacreatetime(currentDateTime.substring(11));
|
||||
|
||||
String existSql = "select id from " + tableName + " where ibknum='" + ufModel.getIbknum() + "' and actacn='" + ufModel.getActacn() + "' and outref='" + ufModel.getOutref() + "'";
|
||||
rs.execute(existSql);
|
||||
if (rs.next()) {
|
||||
billId = rs.getInt("id");
|
||||
String msg = update(modelName, tableName, ufModel);
|
||||
if (!"".equals(msg)){
|
||||
this.writeLog(modelName + ", 保存异常: " + msg);
|
||||
}
|
||||
return billId;
|
||||
}
|
||||
|
||||
// 获取实体类的所有属性,返回Field数组
|
||||
Field[] field = ufModel.getClass().getDeclaredFields();
|
||||
// 遍历所有属性
|
||||
for (int i = 0; i < field.length; i++) {
|
||||
// 获取属性的名字,并将属性第一个字符大写
|
||||
String name = field[i].getName();
|
||||
name = name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
// 得到属性类型
|
||||
String type = field[i].getGenericType().toString();
|
||||
if (type.equals("class java.lang.String")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
String value = (String) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
fieldSql += "," + name;
|
||||
valueSql += ",'" + value.trim() + "'";
|
||||
}
|
||||
}
|
||||
if (type.equals("class java.lang.Integer")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
Integer value = (Integer) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
fieldSql += "," + name;
|
||||
valueSql += "," + value + "";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!"".equals(fieldSql)) {
|
||||
fieldSql = fieldSql.substring(1);
|
||||
valueSql = valueSql.substring(1);
|
||||
String insertSql = "insert into " + tableName + " (" + fieldSql + ") values (" + valueSql + ")";
|
||||
result = rs.execute(insertSql);
|
||||
if (!result) {
|
||||
return -1;
|
||||
}
|
||||
RecordSet rightRs = new RecordSet();
|
||||
writeLog(modelName + ", insertSql ->" + insertSql + ", result:" + result + ", formmodeid: " + formmodeid);
|
||||
rightRs.execute("SELECT id FROM " + tableName + " where ibknum='" + ufModel.getIbknum() + "' and actacn='" + ufModel.getActacn() + "' and outref='" + ufModel.getOutref() + "'");
|
||||
if (rightRs.next()) {
|
||||
billId = rightRs.getInt("id");
|
||||
this.setModeRight(1, formmodeid, billId);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
writeLog(modelName + ", 新增报错 ->" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
return billId;
|
||||
}
|
||||
|
||||
public String update(String modelName, String tableName, TradeInfo ufModel) throws Exception{
|
||||
writeLog(modelName + ", update -> formmodeid: " + formmodeid);
|
||||
RecordSet rs = new RecordSet();
|
||||
String setSql = "";
|
||||
boolean result = false;
|
||||
|
||||
try {
|
||||
// 获取实体类的所有属性,返回Field数组
|
||||
Field[] field = ufModel.getClass().getDeclaredFields();
|
||||
// 遍历所有属性
|
||||
for(int i = 0; i < field.length; i++) {
|
||||
// 获取属性的名字,并将属性第一个字符大写
|
||||
String name = field[i].getName();
|
||||
name = name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
// 主键不更新
|
||||
if("Ibknum".equals(name) || "Actacn".equals(name) || "Curcde".equals(name) || "Baldat".equals(name) || "Modedatacreatedate".equals(name) || "Modedatacreatetime".equals(name)) {
|
||||
continue;
|
||||
}
|
||||
// 得到属性类型
|
||||
String type = field[i].getGenericType().toString();
|
||||
if (type.equals("class java.lang.String")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
String value = (String) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
setSql += "," + name + "='" + value + "'";
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals("class java.lang.Integer")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
Integer value = (Integer) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
setSql += "," + name + "=" + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!"".equals(setSql)) {
|
||||
setSql = setSql.substring(1);
|
||||
String updateSql = "update " + tableName + " set " + setSql + " where ibknum='" + ufModel.getIbknum() + "' and actacn='" + ufModel.getActacn() + "' and outref='" + ufModel.getOutref() + "'";
|
||||
writeLog(modelName + ", updateSql ->" + updateSql);
|
||||
result = rs.execute(updateSql);
|
||||
if (!result){
|
||||
return "修改失败";
|
||||
}
|
||||
}
|
||||
} catch (Exception e){
|
||||
writeLog(modelName + ", 修改报错 ->" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return e.getMessage();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public void setModeRight(int creater, int modeid, int sourceid) {
|
||||
ModeRightInfo moderightinfo = new ModeRightInfo();
|
||||
moderightinfo.setNewRight(true);
|
||||
moderightinfo.editModeDataShare(creater, modeid, sourceid);
|
||||
}
|
||||
|
||||
|
||||
public Integer getFormmodeid() {
|
||||
return formmodeid;
|
||||
}
|
||||
|
||||
public void setFormmodeid(Integer formmodeid) {
|
||||
this.formmodeid = formmodeid;
|
||||
}
|
||||
|
||||
public String getModedatacreater() {
|
||||
return modedatacreater;
|
||||
}
|
||||
|
||||
public void setModedatacreater(String modedatacreater) {
|
||||
this.modedatacreater = modedatacreater;
|
||||
}
|
||||
|
||||
public String getModedatacreatertype() {
|
||||
return modedatacreatertype;
|
||||
}
|
||||
|
||||
public void setModedatacreatertype(String modedatacreatertype) {
|
||||
this.modedatacreatertype = modedatacreatertype;
|
||||
}
|
||||
|
||||
public String getModedatacreatedate() {
|
||||
return modedatacreatedate;
|
||||
}
|
||||
|
||||
public void setModedatacreatedate(String modedatacreatedate) {
|
||||
this.modedatacreatedate = modedatacreatedate;
|
||||
}
|
||||
|
||||
public String getModedatacreatetime() {
|
||||
return modedatacreatetime;
|
||||
}
|
||||
|
||||
public void setModedatacreatetime(String modedatacreatetime) {
|
||||
this.modedatacreatetime = modedatacreatetime;
|
||||
}
|
||||
|
||||
public String getIbknum() {
|
||||
return ibknum;
|
||||
}
|
||||
|
||||
public void setIbknum(String ibknum) {
|
||||
this.ibknum = ibknum;
|
||||
}
|
||||
|
||||
public String getActacn() {
|
||||
return actacn;
|
||||
}
|
||||
|
||||
public void setActacn(String actacn) {
|
||||
this.actacn = actacn;
|
||||
}
|
||||
|
||||
public String getCurcde() {
|
||||
return curcde;
|
||||
}
|
||||
|
||||
public void setCurcde(String curcde) {
|
||||
this.curcde = curcde;
|
||||
}
|
||||
|
||||
public String getActname() {
|
||||
return actname;
|
||||
}
|
||||
|
||||
public void setActname(String actname) {
|
||||
this.actname = actname;
|
||||
}
|
||||
|
||||
public String getAcntname() {
|
||||
return acntname;
|
||||
}
|
||||
|
||||
public void setAcntname(String acntname) {
|
||||
this.acntname = acntname;
|
||||
}
|
||||
|
||||
public String getIbkname() {
|
||||
return ibkname;
|
||||
}
|
||||
|
||||
public void setIbkname(String ibkname) {
|
||||
this.ibkname = ibkname;
|
||||
}
|
||||
|
||||
public String getOutref() {
|
||||
return outref;
|
||||
}
|
||||
|
||||
public void setOutref(String outref) {
|
||||
this.outref = outref;
|
||||
}
|
||||
|
||||
public String getToibkn() {
|
||||
return toibkn;
|
||||
}
|
||||
|
||||
public void setToibkn(String toibkn) {
|
||||
this.toibkn = toibkn;
|
||||
}
|
||||
|
||||
public String getActacn_receipt() {
|
||||
return actacn_receipt;
|
||||
}
|
||||
|
||||
public void setActacn_receipt(String actacn_receipt) {
|
||||
this.actacn_receipt = actacn_receipt;
|
||||
}
|
||||
|
||||
public String getTobref() {
|
||||
return tobref;
|
||||
}
|
||||
|
||||
public void setTobref(String tobref) {
|
||||
this.tobref = tobref;
|
||||
}
|
||||
|
||||
public String getToname() {
|
||||
return toname;
|
||||
}
|
||||
|
||||
public void setToname(String toname) {
|
||||
this.toname = toname;
|
||||
}
|
||||
|
||||
public String getMactibkn() {
|
||||
return mactibkn;
|
||||
}
|
||||
|
||||
public void setMactibkn(String mactibkn) {
|
||||
this.mactibkn = mactibkn;
|
||||
}
|
||||
|
||||
public String getMactacn() {
|
||||
return mactacn;
|
||||
}
|
||||
|
||||
public void setMactacn(String mactacn) {
|
||||
this.mactacn = mactacn;
|
||||
}
|
||||
|
||||
public String getMactname() {
|
||||
return mactname;
|
||||
}
|
||||
|
||||
public void setMactname(String mactname) {
|
||||
this.mactname = mactname;
|
||||
}
|
||||
|
||||
public String getMactbank() {
|
||||
return mactbank;
|
||||
}
|
||||
|
||||
public void setMactbank(String mactbank) {
|
||||
this.mactbank = mactbank;
|
||||
}
|
||||
|
||||
public String getVchnum() {
|
||||
return vchnum;
|
||||
}
|
||||
|
||||
public void setVchnum(String vchnum) {
|
||||
this.vchnum = vchnum;
|
||||
}
|
||||
|
||||
public String getTransid() {
|
||||
return transid;
|
||||
}
|
||||
|
||||
public void setTransid(String transid) {
|
||||
this.transid = transid;
|
||||
}
|
||||
|
||||
public String getInsid() {
|
||||
return insid;
|
||||
}
|
||||
|
||||
public void setInsid(String insid) {
|
||||
this.insid = insid;
|
||||
}
|
||||
|
||||
public String getTxndate_time() {
|
||||
return txndate_time;
|
||||
}
|
||||
|
||||
public void setTxndate_time(String txndate_time) {
|
||||
this.txndate_time = txndate_time;
|
||||
}
|
||||
|
||||
public String getTxnamt() {
|
||||
return txnamt;
|
||||
}
|
||||
|
||||
public void setTxnamt(String txnamt) {
|
||||
this.txnamt = txnamt;
|
||||
}
|
||||
|
||||
public String getAcctbal() {
|
||||
return acctbal;
|
||||
}
|
||||
|
||||
public void setAcctbal(String acctbal) {
|
||||
this.acctbal = acctbal;
|
||||
}
|
||||
|
||||
public String getAvlbal() {
|
||||
return avlbal;
|
||||
}
|
||||
|
||||
public void setAvlbal(String avlbal) {
|
||||
this.avlbal = avlbal;
|
||||
}
|
||||
|
||||
public String getFrzamt() {
|
||||
return frzamt;
|
||||
}
|
||||
|
||||
public void setFrzamt(String frzamt) {
|
||||
this.frzamt = frzamt;
|
||||
}
|
||||
|
||||
public String getOverdramt() {
|
||||
return overdramt;
|
||||
}
|
||||
|
||||
public void setOverdramt(String overdramt) {
|
||||
this.overdramt = overdramt;
|
||||
}
|
||||
|
||||
public String getAvloverdramt() {
|
||||
return avloverdramt;
|
||||
}
|
||||
|
||||
public void setAvloverdramt(String avloverdramt) {
|
||||
this.avloverdramt = avloverdramt;
|
||||
}
|
||||
|
||||
public String getUseinfo() {
|
||||
return useinfo;
|
||||
}
|
||||
|
||||
public void setUseinfo(String useinfo) {
|
||||
this.useinfo = useinfo;
|
||||
}
|
||||
|
||||
public String getFy() {
|
||||
return fy;
|
||||
}
|
||||
|
||||
public void setFy(String fy) {
|
||||
this.fy = fy;
|
||||
}
|
||||
|
||||
public String getTranstype() {
|
||||
return transtype;
|
||||
}
|
||||
|
||||
public void setTranstype(String transtype) {
|
||||
this.transtype = transtype;
|
||||
}
|
||||
|
||||
public String getTrncur() {
|
||||
return trncur;
|
||||
}
|
||||
|
||||
public void setTrncur(String trncur) {
|
||||
this.trncur = trncur;
|
||||
}
|
||||
|
||||
public String getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(String direction) {
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public String getTobank() {
|
||||
return tobank;
|
||||
}
|
||||
|
||||
public void setTobank(String tobank) {
|
||||
this.tobank = tobank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TradeInfo{" +
|
||||
"ibknum='" + ibknum + '\'' +
|
||||
", actacn='" + actacn + '\'' +
|
||||
", curcde='" + curcde + '\'' +
|
||||
", actname='" + actname + '\'' +
|
||||
", acntname='" + acntname + '\'' +
|
||||
", ibkname='" + ibkname + '\'' +
|
||||
", outref='" + outref + '\'' +
|
||||
", toibkn='" + toibkn + '\'' +
|
||||
", actacn_receipt='" + actacn_receipt + '\'' +
|
||||
", tobref='" + tobref + '\'' +
|
||||
", toname='" + toname + '\'' +
|
||||
", mactibkn='" + mactibkn + '\'' +
|
||||
", mactacn='" + mactacn + '\'' +
|
||||
", mactname='" + mactname + '\'' +
|
||||
", mactbank='" + mactbank + '\'' +
|
||||
", vchnum='" + vchnum + '\'' +
|
||||
", transid='" + transid + '\'' +
|
||||
", insid='" + insid + '\'' +
|
||||
", txndate_time='" + txndate_time + '\'' +
|
||||
", txnamt='" + txnamt + '\'' +
|
||||
", acctbal='" + acctbal + '\'' +
|
||||
", avlbal='" + avlbal + '\'' +
|
||||
", frzamt='" + frzamt + '\'' +
|
||||
", overdramt='" + overdramt + '\'' +
|
||||
", avloverdramt='" + avloverdramt + '\'' +
|
||||
", useinfo='" + useinfo + '\'' +
|
||||
", fy='" + fy + '\'' +
|
||||
", transtype='" + transtype + '\'' +
|
||||
", trncur='" + trncur + '\'' +
|
||||
", direction='" + direction + '\'' +
|
||||
", tobank='" + tobank + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,314 @@
|
|||
package com.api.nonstandardext.zenner.model.sap;
|
||||
|
||||
import weaver.conn.RecordSet;
|
||||
import weaver.formmode.setup.ModeRightInfo;
|
||||
import weaver.general.BaseBean;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 期间余额
|
||||
*/
|
||||
public class PeriodBalance extends BaseBean {
|
||||
|
||||
private Integer formmodeid;
|
||||
private String modedatacreater;
|
||||
private String modedatacreatertype;
|
||||
private String modedatacreatedate;
|
||||
private String modedatacreatetime;
|
||||
|
||||
private String IvCompCode;
|
||||
private String IvFiscYear;
|
||||
private String IvFisPeriod;
|
||||
|
||||
//累计余额
|
||||
private String EvBalance;
|
||||
|
||||
//期间余额
|
||||
private String EvPerSales;
|
||||
|
||||
//期间贷方发生额
|
||||
private String EvCreditPer;
|
||||
|
||||
//期间借方发生额
|
||||
private String EvDebitsPer;
|
||||
|
||||
//币种
|
||||
private String EvCurrency;
|
||||
|
||||
//科目
|
||||
private String glAccount;
|
||||
|
||||
public Integer save(PeriodBalance ufModel, Integer formmodeid, String tableName) {
|
||||
|
||||
String modelName = "期间余额";
|
||||
|
||||
Integer billId = 0;
|
||||
|
||||
try {
|
||||
RecordSet rs = new RecordSet();
|
||||
String fieldSql = "";
|
||||
String valueSql = "";
|
||||
boolean result = false;
|
||||
String currentDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
ufModel.setFormmodeid(formmodeid);
|
||||
ufModel.setModedatacreater("1");
|
||||
ufModel.setModedatacreatertype("0");
|
||||
ufModel.setModedatacreatedate(currentDateTime.substring(0, 10));
|
||||
ufModel.setModedatacreatetime(currentDateTime.substring(11));
|
||||
|
||||
String existSql = "select id from " + tableName + " where IvCompCode='" + ufModel.getIvCompCode() + "' and IvFiscYear='" + ufModel.getIvFiscYear() + "' and IvFisPeriod='" + ufModel.getIvFisPeriod() + "'";
|
||||
rs.execute(existSql);
|
||||
if (rs.next()) {
|
||||
billId = rs.getInt("id");
|
||||
String msg = update(modelName, tableName, ufModel);
|
||||
if (!"".equals(msg)){
|
||||
this.writeLog(modelName + ", 保存异常: " + msg);
|
||||
}
|
||||
return billId;
|
||||
}
|
||||
|
||||
// 获取实体类的所有属性,返回Field数组
|
||||
Field[] field = ufModel.getClass().getDeclaredFields();
|
||||
// 遍历所有属性
|
||||
for (int i = 0; i < field.length; i++) {
|
||||
// 获取属性的名字,并将属性第一个字符大写
|
||||
String name = field[i].getName();
|
||||
name = name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
// 得到属性类型
|
||||
String type = field[i].getGenericType().toString();
|
||||
if (type.equals("class java.lang.String")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
String value = (String) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
fieldSql += "," + name;
|
||||
valueSql += ",'" + value.trim() + "'";
|
||||
}
|
||||
}
|
||||
if (type.equals("class java.lang.Integer")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
Integer value = (Integer) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
fieldSql += "," + name;
|
||||
valueSql += "," + value + "";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!"".equals(fieldSql)) {
|
||||
fieldSql = fieldSql.substring(1);
|
||||
valueSql = valueSql.substring(1);
|
||||
String insertSql = "insert into " + tableName + " (" + fieldSql + ") values (" + valueSql + ")";
|
||||
result = rs.execute(insertSql);
|
||||
if (!result) {
|
||||
return -1;
|
||||
}
|
||||
RecordSet rightRs = new RecordSet();
|
||||
writeLog(modelName + ", insertSql ->" + insertSql + ", result:" + result + ", formmodeid: " + formmodeid);
|
||||
rightRs.execute("SELECT id FROM " + tableName + " where IvCompCode='" + ufModel.getIvCompCode() + "' and IvFiscYear='" + ufModel.getIvFiscYear() + "' and IvFisPeriod='" + ufModel.getIvFisPeriod() + "'");
|
||||
if (rightRs.next()) {
|
||||
billId = rightRs.getInt("id");
|
||||
this.setModeRight(1, formmodeid, billId);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
writeLog(modelName + ", 新增报错 ->" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
return billId;
|
||||
}
|
||||
|
||||
public String update(String modelName, String tableName, PeriodBalance ufModel) throws Exception{
|
||||
writeLog(modelName + ", update -> formmodeid: " + formmodeid);
|
||||
RecordSet rs = new RecordSet();
|
||||
String setSql = "";
|
||||
boolean result = false;
|
||||
|
||||
try {
|
||||
// 获取实体类的所有属性,返回Field数组
|
||||
Field[] field = ufModel.getClass().getDeclaredFields();
|
||||
// 遍历所有属性
|
||||
for(int i = 0; i < field.length; i++) {
|
||||
// 获取属性的名字,并将属性第一个字符大写
|
||||
String name = field[i].getName();
|
||||
name = name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
// 主键不更新
|
||||
if("IvCompCode".equals(name) || "IvFiscYear".equals(name) || "IvFisPeriod".equals(name) || "Modedatacreatedate".equals(name) || "Modedatacreatetime".equals(name)) {
|
||||
continue;
|
||||
}
|
||||
// 得到属性类型
|
||||
String type = field[i].getGenericType().toString();
|
||||
if (type.equals("class java.lang.String")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
String value = (String) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
setSql += "," + name + "='" + value + "'";
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals("class java.lang.Integer")) {
|
||||
Method m = ufModel.getClass().getMethod("get" + name);
|
||||
// 调用getter方法获取属性值
|
||||
Integer value = (Integer) m.invoke(ufModel);
|
||||
if (value != null) {
|
||||
setSql += "," + name + "=" + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!"".equals(setSql)) {
|
||||
setSql = setSql.substring(1);
|
||||
String updateSql = "update " + tableName + " set " + setSql + " where IvCompCode='" + ufModel.getIvCompCode() + "' and IvFiscYear='" + ufModel.getIvFiscYear() + "' and IvFisPeriod='" + ufModel.getIvFisPeriod() + "'";
|
||||
writeLog(modelName + ", updateSql ->" + updateSql);
|
||||
result = rs.execute(updateSql);
|
||||
if (!result){
|
||||
return "修改失败";
|
||||
}
|
||||
}
|
||||
} catch (Exception e){
|
||||
writeLog(modelName + ", 修改报错 ->" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return e.getMessage();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public void setModeRight(int creater, int modeid, int sourceid) {
|
||||
ModeRightInfo moderightinfo = new ModeRightInfo();
|
||||
moderightinfo.setNewRight(true);
|
||||
moderightinfo.editModeDataShare(creater, modeid, sourceid);
|
||||
}
|
||||
|
||||
|
||||
public Integer getFormmodeid() {
|
||||
return formmodeid;
|
||||
}
|
||||
|
||||
public void setFormmodeid(Integer formmodeid) {
|
||||
this.formmodeid = formmodeid;
|
||||
}
|
||||
|
||||
public String getModedatacreater() {
|
||||
return modedatacreater;
|
||||
}
|
||||
|
||||
public void setModedatacreater(String modedatacreater) {
|
||||
this.modedatacreater = modedatacreater;
|
||||
}
|
||||
|
||||
public String getModedatacreatertype() {
|
||||
return modedatacreatertype;
|
||||
}
|
||||
|
||||
public void setModedatacreatertype(String modedatacreatertype) {
|
||||
this.modedatacreatertype = modedatacreatertype;
|
||||
}
|
||||
|
||||
public String getModedatacreatedate() {
|
||||
return modedatacreatedate;
|
||||
}
|
||||
|
||||
public void setModedatacreatedate(String modedatacreatedate) {
|
||||
this.modedatacreatedate = modedatacreatedate;
|
||||
}
|
||||
|
||||
public String getModedatacreatetime() {
|
||||
return modedatacreatetime;
|
||||
}
|
||||
|
||||
public void setModedatacreatetime(String modedatacreatetime) {
|
||||
this.modedatacreatetime = modedatacreatetime;
|
||||
}
|
||||
|
||||
public String getEvBalance() {
|
||||
return EvBalance;
|
||||
}
|
||||
|
||||
public void setEvBalance(String evBalance) {
|
||||
EvBalance = evBalance;
|
||||
}
|
||||
|
||||
public String getEvPerSales() {
|
||||
return EvPerSales;
|
||||
}
|
||||
|
||||
public void setEvPerSales(String evPerSales) {
|
||||
EvPerSales = evPerSales;
|
||||
}
|
||||
|
||||
public String getEvCreditPer() {
|
||||
return EvCreditPer;
|
||||
}
|
||||
|
||||
public void setEvCreditPer(String evCreditPer) {
|
||||
EvCreditPer = evCreditPer;
|
||||
}
|
||||
|
||||
public String getEvDebitsPer() {
|
||||
return EvDebitsPer;
|
||||
}
|
||||
|
||||
public void setEvDebitsPer(String evDebitsPer) {
|
||||
EvDebitsPer = evDebitsPer;
|
||||
}
|
||||
|
||||
public String getEvCurrency() {
|
||||
return EvCurrency;
|
||||
}
|
||||
|
||||
public void setEvCurrency(String evCurrency) {
|
||||
EvCurrency = evCurrency;
|
||||
}
|
||||
|
||||
public String getGlAccount() {
|
||||
return glAccount;
|
||||
}
|
||||
|
||||
public void setGlAccount(String glAccount) {
|
||||
this.glAccount = glAccount;
|
||||
}
|
||||
|
||||
public String getIvCompCode() {
|
||||
return IvCompCode;
|
||||
}
|
||||
|
||||
public void setIvCompCode(String ivCompCode) {
|
||||
IvCompCode = ivCompCode;
|
||||
}
|
||||
|
||||
public String getIvFiscYear() {
|
||||
return IvFiscYear;
|
||||
}
|
||||
|
||||
public void setIvFiscYear(String ivFiscYear) {
|
||||
IvFiscYear = ivFiscYear;
|
||||
}
|
||||
|
||||
public String getIvFisPeriod() {
|
||||
return IvFisPeriod;
|
||||
}
|
||||
|
||||
public void setIvFisPeriod(String ivFisPeriod) {
|
||||
IvFisPeriod = ivFisPeriod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PeriodBalance{" +
|
||||
"IvCompCode='" + IvCompCode + '\'' +
|
||||
", IvFiscYear='" + IvFiscYear + '\'' +
|
||||
", IvFisPeriod='" + IvFisPeriod + '\'' +
|
||||
", EvBalance='" + EvBalance + '\'' +
|
||||
", EvPerSales='" + EvPerSales + '\'' +
|
||||
", EvCreditPer='" + EvCreditPer + '\'' +
|
||||
", EvDebitsPer='" + EvDebitsPer + '\'' +
|
||||
", EvCurrency='" + EvCurrency + '\'' +
|
||||
", glAccount='" + glAccount + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue