diff --git a/79b1fe79-9272-4270-9baa-25c339a705a3_商品销售统计.xlsx b/79b1fe79-9272-4270-9baa-25c339a705a3_商品销售统计.xlsx new file mode 100644 index 0000000..fe5f6ae Binary files /dev/null and b/79b1fe79-9272-4270-9baa-25c339a705a3_商品销售统计.xlsx differ diff --git a/a543d9e9-238d-4815-9ef9-1e3a228e1865_商品销售统计.xlsx b/a543d9e9-238d-4815-9ef9-1e3a228e1865_商品销售统计.xlsx new file mode 100644 index 0000000..ed901fd Binary files /dev/null and b/a543d9e9-238d-4815-9ef9-1e3a228e1865_商品销售统计.xlsx differ diff --git a/af94f4ed-edcf-457f-a384-046615f74e02_商品销售统计.xlsx b/af94f4ed-edcf-457f-a384-046615f74e02_商品销售统计.xlsx new file mode 100644 index 0000000..d6ba085 Binary files /dev/null and b/af94f4ed-edcf-457f-a384-046615f74e02_商品销售统计.xlsx differ diff --git a/bad59ad9-68d6-4d83-ac6f-eb4830c940d2_商品销售统计.xlsx b/bad59ad9-68d6-4d83-ac6f-eb4830c940d2_商品销售统计.xlsx new file mode 100644 index 0000000..e0fe6aa Binary files /dev/null and b/bad59ad9-68d6-4d83-ac6f-eb4830c940d2_商品销售统计.xlsx differ diff --git a/bwie-common/pom.xml b/bwie-common/pom.xml index 0e5576b..3d0fe36 100644 --- a/bwie-common/pom.xml +++ b/bwie-common/pom.xml @@ -132,6 +132,30 @@ 9.3.7.v20160115 + + + + org.apache.poi + poi-ooxml + 3.17 + + + org.apache.poi + poi-ooxml-schemas + 3.17 + + + org.apache.commons + commons-lang3 + 3.12.0 + + + + com.alibaba + easyexcel + 2.2.7 + + diff --git a/bwie-common/src/main/java/com/bwie/common/pojo/Sell.java b/bwie-common/src/main/java/com/bwie/common/pojo/Sell.java new file mode 100644 index 0000000..219a8e9 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/pojo/Sell.java @@ -0,0 +1,114 @@ +package com.bwie.common.pojo; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.bwie.common.utils.poi.annotation.Excel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * @author 86175 + * 记录销售记录 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Sell { + + /** + * 销售编号 + */ + @ExcelIgnore + private Integer sellId; + /** + * 商品编号 + */ + @ExcelIgnore + private Integer shopId; + /** + * 卖出的时间 + */ + @Excel(name = "卖出商品的时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date sellTime; + /** + * 用户 + */ + @ExcelIgnore + private Integer userId; + /** + * 设备表 + */ + @ExcelIgnore + private Integer facilityId; + /** + * 设备类型 + */ + @Excel(name = "设备类型") + private String facilityType; + /** + * 设备地址 + */ + @Excel(name = "设备地址") + private String facilitySite; + /** + * 补货员工 + */ + @Excel(name = "补货员工") + private Integer replenishmentUserId; + /** + * 维修员工 + */ + @Excel(name = "维修员工") + private Integer maintainUserId; + /** + * 设备状态 + */ + @Excel(name = "设备状态") + private String facilityStatic; + /** + * 删除状态 + */ + @ExcelIgnore + private Integer delId; + /** + * 商品名称 + */ + @Excel(name = "商品名称") + private String shopName; + /** + * 商品价格 + */ + @Excel(name = "商品价格") + private Double shopPrice; + /** + * 类型编号 + */ + @ExcelIgnore + private Integer typeId; + /** + * 商品类型 + */ + @Excel(name = "商品类型") + private String typeName; + /** + * 用户名 + */ + @Excel(name = "用户名") + public String userName; + /** + * 手机号 + */ + @Excel(name = "手机号") + public String phone; + /** + * 邮箱 + */ + @Excel(name = "邮箱") + public String email; + + +} diff --git a/bwie-common/src/main/java/com/bwie/common/pojo/VO/VOSell.java b/bwie-common/src/main/java/com/bwie/common/pojo/VO/VOSell.java new file mode 100644 index 0000000..e19e94f --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/pojo/VO/VOSell.java @@ -0,0 +1,31 @@ +package com.bwie.common.pojo.VO; + +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 传参 + * @author 86175 + */ +@Data +public class VOSell { + + /** + * 商品编号 + */ + private Integer shopId; + /** + * 卖出的时间 + */ + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date sellTime; + /** + * 用户 + */ + private Integer userId; + + + +} diff --git a/bwie-common/src/main/java/com/bwie/common/result/Result.java b/bwie-common/src/main/java/com/bwie/common/result/Result.java index 30b1e73..45f75ff 100644 --- a/bwie-common/src/main/java/com/bwie/common/result/Result.java +++ b/bwie-common/src/main/java/com/bwie/common/result/Result.java @@ -73,4 +73,28 @@ public class Result implements Serializable { apiResult.setMsg(msg); return apiResult; } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } } diff --git a/bwie-common/src/main/java/com/bwie/common/utils/WebMvcConfig.java b/bwie-common/src/main/java/com/bwie/common/utils/WebMvcConfig.java new file mode 100644 index 0000000..a5f29e3 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/WebMvcConfig.java @@ -0,0 +1,22 @@ +//package com.bwie.common.utils; +// +//import org.springframework.context.annotation.Configuration; +//import org.springframework.http.converter.HttpMessageConverter; +//import org.springframework.stereotype.Component; +//import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +// +//import java.util.List; +// +///** +// * @author 86175 +// * 消息转换器 +// */ +//@Configuration +//public class WebMvcConfig implements WebMvcConfigurer { +// +// @Override +// public void configureMessageConverters(List> converters) { +//// converters.add(new ExcelMessageConverter()); +// } +// +//} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/core/date/DateUtils.java b/bwie-common/src/main/java/com/bwie/common/utils/core/date/DateUtils.java new file mode 100644 index 0000000..8d60608 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/core/date/DateUtils.java @@ -0,0 +1,137 @@ +package com.bwie.common.utils.core.date; + +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.io.File; +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 时间工具类 + * + * @author markGuo + */ +public class DateUtils extends org.apache.commons.lang3.time.DateUtils +{ + public static String YYYY = "yyyy"; + + public static String YYYY_MM = "yyyy-MM"; + + public static String YYYY_MM_DD = "yyyy-MM-dd"; + + public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; + + public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + + private static String[] parsePatterns = { + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; + + /** + * 获取当前Date型日期 + * + * @return Date() 当前日期 + */ + public static Date getNowDate() { + return new Date(); + } + + /** + * 获取当前日期, 默认格式为yyyy-MM-dd + * + * @return String + */ + public static String getDate() { + return dateTimeNow(YYYY_MM_DD); + } + + public static final String getTime() { + return dateTimeNow(YYYY_MM_DD_HH_MM_SS); + } + + public static final String dateTimeNow() { + return dateTimeNow(YYYYMMDDHHMMSS); + } + + public static final String dateTimeNow(final String format) { + return parseDateToStr(format, new Date()); + } + + public static final String dateTime(final Date date) { + return parseDateToStr(YYYY_MM_DD, date); + } + + public static final String parseDateToStr(final String format, final Date date) { + return new SimpleDateFormat(format).format(date); + } + + public static final Date dateTime(final String format, final String ts) { + try { + return new SimpleDateFormat(format).parse(ts); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * 日期路径 即年/月/日 如2018/08/08 + */ + public static final String datePath() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyy"+File.separator+"MM"+ File.separator +"dd"); + } + + /** + * 日期路径 即年/月/日 如20180808 + */ + public static final String dateTime() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyyMMdd"); + } + + /** + * 日期型字符串转化为日期 格式 + */ + public static Date parseDate(Object str) { + if (str == null) { + return null; + } + try { + return parseDate(str.toString(), parsePatterns); + } catch (ParseException e) { + return null; + } + } + + /** + * 获取服务器启动时间 + */ + public static Date getServerStartDate() { + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(time); + } + + /** + * 计算两个时间差 + */ + public static String getDatePoor(Date endDate, Date nowDate) { + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // long ns = 1000; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - nowDate.getTime(); + // 计算差多少天 + long day = diff / nd; + // 计算差多少小时 + long hour = diff % nd / nh; + // 计算差多少分钟 + long min = diff % nd % nh / nm; + // 计算差多少秒//输出结果 + // long sec = diff % nd % nh % nm / ns; + return day + "天" + hour + "小时" + min + "分钟"; + } +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/core/reflect/ReflectUtils.java b/bwie-common/src/main/java/com/bwie/common/utils/core/reflect/ReflectUtils.java new file mode 100644 index 0000000..80e4426 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/core/reflect/ReflectUtils.java @@ -0,0 +1,386 @@ +package com.bwie.common.utils.core.reflect; + +import com.bwie.common.utils.core.date.DateUtils; +import com.bwie.common.utils.core.text.Convert; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.*; +import java.util.Date; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * + * @author markGuo + */ +@SuppressWarnings("rawtypes") +public class ReflectUtils { + /** + * set方法前缀 + */ + private static final String SETTER_PREFIX = "set"; + + /** + * get方法前缀 + */ + private static final String GETTER_PREFIX = "get"; + + /** + * CGLIB 类分隔符 + */ + private static final String CGLIB_CLASS_SEPARATOR = "$$"; + + /** + * 日志 + */ + private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class); + + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + * @param obj + * @param propertyName + * @param + * @return + */ + @SuppressWarnings("unchecked") + public static E invokeGetter(Object obj, String propertyName) { + Object object = obj; + for (String name : StringUtils.split(propertyName, ".")) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + return (E) object; + } + + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + * @param obj + * @param propertyName + * @param value + * @param + */ + public static void invokeSetter(Object obj, String propertyName, E value) { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i = 0; i < names.length; i++) { + if (i < names.length - 1) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); + object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } else { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + invokeMethodByName(object, setterMethodName, new Object[] { value }); + } + } + } + + /** + * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. + * @param obj + * @param fieldName + * @param + * @return + */ + @SuppressWarnings("unchecked") + public static E getFieldValue(final Object obj, final String fieldName) { + Field field = getAccessibleField(obj, fieldName); + if (field == null) { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return null; + } + E result = null; + try { + result = (E) field.get(obj); + } catch (IllegalAccessException e) { + logger.error("不可能抛出的异常{}", e.getMessage()); + } + return result; + } + + /** + * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. + * @param obj + * @param fieldName + * @param value + * @param + */ + public static void setFieldValue(final Object obj, final String fieldName, final E value) { + Field field = getAccessibleField(obj, fieldName); + if (field == null) { + // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return; + } + try { + field.set(obj, value); + } catch (IllegalAccessException e) { + logger.error("不可能抛出的异常: {}", e.getMessage()); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符. + * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. + * 同时匹配方法名+参数类型, + * @param obj + * @param methodName + * @param parameterTypes + * @param args + * @param + * @return + */ + @SuppressWarnings("unchecked") + public static E invokeMethod(final Object obj, final String methodName, final Class[] parameterTypes, + final Object[] args) { + if (obj == null || methodName == null) { + return null; + } + Method method = getAccessibleMethod(obj, methodName, parameterTypes); + if (method == null) { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try { + return (E) method.invoke(obj, args); + } catch (Exception e) { + String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符, + * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. + * 只匹配函数名,如果有多个同名函数调用第一个。 + * @param obj + * @param methodName + * @param args + * @param + * @return + */ + @SuppressWarnings("unchecked") + public static E invokeMethodByName(final Object obj, final String methodName, final Object[] args) { + Method method = getAccessibleMethodByName(obj, methodName, args.length); + if (method == null) { + // 如果为空不报错,直接返回空。 + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try { + // 类型转换(将参数数据类型转换为目标方法参数类型) + Class[] cs = method.getParameterTypes(); + for (int i = 0; i < cs.length; i++) { + if (args[i] != null && !args[i].getClass().equals(cs[i])) { + if (cs[i] == String.class) { + args[i] = Convert.toStr(args[i]); + if (StringUtils.endsWith((String) args[i], ".0")) { + args[i] = StringUtils.substringBefore((String) args[i], ".0"); + } + } else if (cs[i] == Integer.class) { + args[i] = Convert.toInt(args[i]); + } else if (cs[i] == Long.class) { + args[i] = Convert.toLong(args[i]); + } else if (cs[i] == Double.class) { + args[i] = Convert.toDouble(args[i]); + } else if (cs[i] == Float.class) { + args[i] = Convert.toFloat(args[i]); + } else if (cs[i] == Date.class) { + if (args[i] instanceof String) { + args[i] = DateUtils.parseDate(args[i]); + } + } + } + } + return (E) method.invoke(obj, args); + } catch (Exception e) { + String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * @param obj + * @param fieldName + * @return + */ + public static Field getAccessibleField(final Object obj, final String fieldName) { + // 为空不报错。直接返回 null + if (obj == null) { + return null; + } + Validate.notBlank(fieldName, "fieldName can't be blank"); + for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { + try { + Field field = superClass.getDeclaredField(fieldName); + makeAccessible(field); + return field; + } + catch (NoSuchFieldException e) { + continue; + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 匹配函数名+参数类型。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + * @param obj + * @param methodName + * @param parameterTypes + * @return + */ + public static Method getAccessibleMethod(final Object obj, final String methodName, + final Class... parameterTypes) { + // 为空不报错。直接返回 null + if (obj == null) { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { + try { + Method method = searchType.getDeclaredMethod(methodName, parameterTypes); + makeAccessible(method); + return method; + } catch (NoSuchMethodException e) { + continue; + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 只匹配函数名。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + * @param obj + * @param methodName + * @param argsNum + * @return + */ + public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) { + // 为空不报错。直接返回 null + if (obj == null) { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { + Method[] methods = searchType.getDeclaredMethods(); + for (Method method : methods) { + if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) { + makeAccessible(method); + return method; + } + } + } + return null; + } + + /** + * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + * @param method + */ + public static void makeAccessible(Method method) { + if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) + && !method.isAccessible()) { + method.setAccessible(true); + } + } + + /** + * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + * @param field + */ + public static void makeAccessible(Field field) { + if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) + || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) { + field.setAccessible(true); + } + } + + /** + * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 + * 如无法找到, 返回Object.class. + * @param clazz + * @param + * @return + */ + @SuppressWarnings("unchecked") + public static Class getClassGenricType(final Class clazz) { + return getClassGenricType(clazz, 0); + } + + /** + * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. + * 如无法找到, 返回Object.class. + * @param clazz + * @param index + * @return + */ + public static Class getClassGenricType(final Class clazz, final int index) { + Type genType = clazz.getGenericSuperclass(); + + if (!(genType instanceof ParameterizedType)) { + logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType"); + return Object.class; + } + + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + + if (index >= params.length || index < 0) { + logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + + params.length); + return Object.class; + } + if (!(params[index] instanceof Class)) { + logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); + return Object.class; + } + + return (Class) params[index]; + } + + /** + * 通过实例化对象获取反射对象 + * @param instance + * @return + */ + public static Class getUserClass(Object instance) { + if (instance == null) { + throw new RuntimeException("Instance must not be null"); + } + Class clazz = instance.getClass(); + if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { + Class superClass = clazz.getSuperclass(); + if (superClass != null && !Object.class.equals(superClass)) { + return superClass; + } + } + return clazz; + + } + + /** + * 将反射时的checked exception转换为unchecked exception. + * @param msg + * @param e + * @return + */ + public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) { + if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException + || e instanceof NoSuchMethodException) { + return new IllegalArgumentException(msg, e); + } else if (e instanceof InvocationTargetException) { + return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException()); + } + return new RuntimeException(msg, e); + } +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/core/spring/SpringUtils.java b/bwie-common/src/main/java/com/bwie/common/utils/core/spring/SpringUtils.java new file mode 100644 index 0000000..68a2ef6 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/core/spring/SpringUtils.java @@ -0,0 +1,106 @@ +package com.bwie.common.utils.core.spring; + +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.stereotype.Component; + +/** + * spring工具类 方便在非spring管理环境中获取bean + * + * @author markGuo + */ +@Component +public final class SpringUtils implements BeanFactoryPostProcessor +{ + /** Spring应用上下文环境 */ + private static ConfigurableListableBeanFactory beanFactory; + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + SpringUtils.beanFactory = beanFactory; + } + + /** + * 获取对象 + * + * @param name + * @return Object 一个以所给名字注册的bean的实例 + * @throws BeansException + * + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) throws BeansException { + return (T) beanFactory.getBean(name); + } + + /** + * 获取类型为requiredType的对象 + * + * @param clz + * @return + * @throws BeansException + * + */ + public static T getBean(Class clz) throws BeansException { + T result = beanFactory.getBean(clz); + return result; + } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) { + return beanFactory.containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws NoSuchBeanDefinitionException + * + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return beanFactory.isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws NoSuchBeanDefinitionException + * + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException { + return beanFactory.getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws NoSuchBeanDefinitionException + * + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return beanFactory.getAliases(name); + } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) { + return (T) AopContext.currentProxy(); + } +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/core/text/CharsetKit.java b/bwie-common/src/main/java/com/bwie/common/utils/core/text/CharsetKit.java new file mode 100644 index 0000000..eca5c63 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/core/text/CharsetKit.java @@ -0,0 +1,78 @@ +package com.bwie.common.utils.core.text; + +import org.apache.commons.lang3.StringUtils; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * 字符集工具类 + * + * @author markGuo + */ +public class CharsetKit +{ + /** ISO-8859-1 */ + public static final String ISO_8859_1 = "ISO-8859-1"; + /** UTF-8 */ + public static final String UTF_8 = "UTF-8"; + /** GBK */ + public static final String GBK = "GBK"; + + /** ISO-8859-1 */ + public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); + /** UTF-8 */ + public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); + /** GBK */ + public static final Charset CHARSET_GBK = Charset.forName(GBK); + + /** + * 转换为Charset对象 + * + * @param charset 字符集,为空则返回默认字符集 + * @return Charset + */ + public static Charset charset(String charset) { + return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, String srcCharset, String destCharset) { + return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, Charset srcCharset, Charset destCharset) { + if (null == srcCharset) { + srcCharset = StandardCharsets.ISO_8859_1; + } + if (null == destCharset) { + srcCharset = StandardCharsets.UTF_8; + } + if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) { + return source; + } + return new String(source.getBytes(srcCharset), destCharset); + } + + /** + * @return 系统字符集编码 + */ + public static String systemCharset() { + return Charset.defaultCharset().name(); + } +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/core/text/Convert.java b/bwie-common/src/main/java/com/bwie/common/utils/core/text/Convert.java new file mode 100644 index 0000000..e3a6698 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/core/text/Convert.java @@ -0,0 +1,818 @@ +package com.bwie.common.utils.core.text; + + +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.text.NumberFormat; +import java.util.Set; + +/** + * 类型转换器 + * + * @author markGuo + */ +public class Convert { + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static String toStr(Object value, String defaultValue) { + if (null == value) { + return defaultValue; + } + if (value instanceof String) { + return (String) value; + } + return value.toString(); + } + + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static String toStr(Object value) { + return toStr(value, null); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Character toChar(Object value, Character defaultValue) { + if (null == value) { + return defaultValue; + } + if (value instanceof Character) { + return (Character) value; + } + + final String valueStr = toStr(value, null); + return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Character toChar(Object value) { + return toChar(value, null); + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Byte toByte(Object value, Byte defaultValue) { + if (value == null) { + return defaultValue; + } else if (value instanceof Byte) { + return (Byte) value; + }else if (value instanceof Number) { + return ((Number) value).byteValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Byte.parseByte(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Byte toByte(Object value) { + return toByte(value, null); + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Short toShort(Object value, Short defaultValue) { + if (value == null) { + return defaultValue; + }else if (value instanceof Short) { + return (Short) value; + } else if (value instanceof Number) { + return ((Number) value).shortValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Short.parseShort(valueStr.trim()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Short toShort(Object value) { + return toShort(value, null); + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Number toNumber(Object value, Number defaultValue) { + if (value == null) { + return defaultValue; + } else if (value instanceof Number) { + return (Number) value; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return NumberFormat.getInstance().parse(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Number toNumber(Object value) { + return toNumber(value, null); + } + + /** + * 转换为int
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Integer toInt(Object value, Integer defaultValue) { + if (value == null) { + return defaultValue; + } else if (value instanceof Integer) { + return (Integer) value; + } else if (value instanceof Number) { + return ((Number) value).intValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Integer.parseInt(valueStr.trim()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为int
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Integer toInt(Object value) { + return toInt(value, null); + } + + /** + * 转换为Integer数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String str) { + return toIntArray(",", str); + } + + /** + * 转换为Long数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String str) { + return toLongArray(",", str); + } + + /** + * 转换为Integer数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String split, String str) { + if (StringUtils.isEmpty(str)) { + return new Integer[] {}; + } + String[] arr = str.split(split); + final Integer[] ints = new Integer[arr.length]; + for (int i = 0; i < arr.length; i++) { + final Integer v = toInt(arr[i], 0); + ints[i] = v; + } + return ints; + } + + /** + * 转换为Long数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String split, String str) { + if (StringUtils.isEmpty(str)) { + return new Long[] {}; + } + String[] arr = str.split(split); + final Long[] longs = new Long[arr.length]; + for (int i = 0; i < arr.length; i++) { + final Long v = toLong(arr[i], null); + longs[i] = v; + } + return longs; + } + + /** + * 转换为String数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String str) { + return toStrArray(",", str); + } + + /** + * 转换为String数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String split, String str) { + return str.split(split); + } + + /** + * 转换为long
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Long toLong(Object value, Long defaultValue) { + if (value == null) { + return defaultValue; + } else if (value instanceof Long) { + return (Long) value; + } else if (value instanceof Number) { + return ((Number) value).longValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).longValue(); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为long
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Long toLong(Object value) { + return toLong(value, null); + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Double toDouble(Object value, Double defaultValue) { + if (value == null) { + return defaultValue; + } else if (value instanceof Double) { + return (Double) value; + } else if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).doubleValue(); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Double toDouble(Object value) { + return toDouble(value, null); + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Float toFloat(Object value, Float defaultValue) { + if (value == null) { + return defaultValue; + } else if (value instanceof Float) { + return (Float) value; + } else if (value instanceof Number) { + return ((Number) value).floatValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Float.parseFloat(valueStr.trim()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Float toFloat(Object value) { + return toFloat(value, null); + } + + /** + * 转换为boolean
+ * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Boolean toBool(Object value, Boolean defaultValue) { + if (value == null) { + return defaultValue; + } else if (value instanceof Boolean) { + return (Boolean) value; + } + String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + valueStr = valueStr.trim().toLowerCase(); + switch (valueStr) { + case "true": + return true; + case "false": + return false; + case "yes": + return true; + case "ok": + return true; + case "no": + return false; + case "1": + return true; + case "0": + return false; + default: + return defaultValue; + } + } + + /** + * 转换为boolean
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Boolean toBool(Object value) { + return toBool(value, null); + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * + * @param clazz Enum的Class + * @param value 值 + * @param defaultValue 默认值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value, E defaultValue) { + if (value == null) { + return defaultValue; + } else if (clazz.isAssignableFrom(value.getClass())) { + @SuppressWarnings("unchecked") + E myE = (E) value; + return myE; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Enum.valueOf(clazz, valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * + * @param clazz Enum的Class + * @param value 值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value) { + return toEnum(clazz, value, null); + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value, BigInteger defaultValue) { + if (value == null) { + return defaultValue; + } else if (value instanceof BigInteger) { + return (BigInteger) value; + } else if (value instanceof Long) { + return BigInteger.valueOf((Long) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return new BigInteger(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value) { + return toBigInteger(value, null); + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) { + if (value == null) { + return defaultValue; + } else if (value instanceof BigDecimal) { + return (BigDecimal) value; + } else if (value instanceof Long) { + return new BigDecimal((Long) value); + } else if (value instanceof Double) { + return new BigDecimal((Double) value); + } else if (value instanceof Integer) { + return new BigDecimal((Integer) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return new BigDecimal(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value) { + return toBigDecimal(value, null); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @return 字符串 + */ + public static String utf8Str(Object obj) { + return str(obj, CharsetKit.CHARSET_UTF_8); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charsetName 字符集 + * @return 字符串 + */ + public static String str(Object obj, String charsetName) { + return str(obj, Charset.forName(charsetName)); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(Object obj, Charset charset) { + if (null == obj) { + return null; + } else if (obj instanceof String) { + return (String) obj; + } else if (obj instanceof byte[] || obj instanceof Byte[]) { + return str(obj, charset); + } else if (obj instanceof ByteBuffer) { + return str((ByteBuffer) obj, charset); + } + return obj.toString(); + } + + /** + * 将byte数组转为字符串 + * + * @param bytes byte数组 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(byte[] bytes, String charset) { + return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + } + + /** + * 解码字节码 + * + * @param data 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * @return 解码后的字符串 + */ + public static String str(byte[] data, Charset charset) { + if (data == null) { + return null; + } else if (null == charset) { + return new String(data); + } + return new String(data, charset); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, String charset) { + if (data == null) { + return null; + } + return str(data, Charset.forName(charset)); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, Charset charset) { + if (null == charset) { + charset = Charset.defaultCharset(); + } + return charset.decode(data).toString(); + } + + // ----------------------------------------------------------------------- 全角半角转换 + /** + * 半角转全角 + * + * @param input String. + * @return 全角字符串. + */ + public static String toSBC(String input) { + return toSBC(input, null); + } + + /** + * 半角转全角 + * + * @param input String + * @param notConvertSet 不替换的字符集合 + * @return 全角字符串. + */ + public static String toSBC(String input, Set notConvertSet) { + char c[] = input.toCharArray(); + for (int i = 0; i < c.length; i++) { + if (null != notConvertSet && notConvertSet.contains(c[i])) { + // 跳过不替换的字符 + continue; + } else if (c[i] == ' ') { + c[i] = '\u3000'; + } else if (c[i] < '\177') { + c[i] = (char) (c[i] + 65248); + + } + } + return new String(c); + } + + /** + * 全角转半角 + * + * @param input String. + * @return 半角字符串 + */ + public static String toDBC(String input) { + return toDBC(input, null); + } + + /** + * 替换全角为半角 + * + * @param text 文本 + * @param notConvertSet 不替换的字符集合 + * @return 替换后的字符 + */ + public static String toDBC(String text, Set notConvertSet) { + char c[] = text.toCharArray(); + for (int i = 0; i < c.length; i++) { + if (null != notConvertSet && notConvertSet.contains(c[i])) { + // 跳过不替换的字符 + continue; + } else if (c[i] == '\u3000') { + c[i] = ' '; + } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') { + c[i] = (char) (c[i] - 65248); + } + } + return new String(c); + } + + /** + * 数字金额大写转换 先写个完整的然后将如零拾替换成零 + * + * @param n 数字 + * @return 中文大写数字 + */ + public static String digitUppercase(double n) { + String[] fraction = { "角", "分" }; + String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; + String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } }; + + String head = n < 0 ? "负" : ""; + n = Math.abs(n); + + String s = ""; + for (int i = 0; i < fraction.length; i++) { + s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); + } + if (s.length() < 1) { + s = "整"; + } + int integerPart = (int) Math.floor(n); + + for (int i = 0; i < unit[0].length && integerPart > 0; i++) { + String p = ""; + for (int j = 0; j < unit[1].length && n > 0; j++) { + p = digit[integerPart % 10] + unit[1][j] + p; + integerPart = integerPart / 10; + } + s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; + } + return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); + } +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/poi/ExcelUtil.java b/bwie-common/src/main/java/com/bwie/common/utils/poi/ExcelUtil.java new file mode 100644 index 0000000..22407e9 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/poi/ExcelUtil.java @@ -0,0 +1,874 @@ +package com.bwie.common.utils.poi; + + +import com.bwie.common.utils.core.date.DateUtils; +import com.bwie.common.utils.core.reflect.ReflectUtils; +import com.bwie.common.utils.core.spring.SpringUtils; +import com.bwie.common.utils.core.text.Convert; +import com.bwie.common.utils.poi.annotation.Excel; +import com.bwie.common.utils.poi.annotation.Excel.Type; +import com.bwie.common.utils.poi.annotation.Excels; +import com.bwie.common.utils.poi.exception.PoiException; +import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.util.*; + +/** + * Excel相关处理 + * + * @author + */ +@Log4j2 +public class ExcelUtil +{ + + /** + * 手动设置表头模板 + */ + private static final String[] TEMPLATE_COLUMNS = { + "员工编号","员工姓名","员工性别","员工年龄","员工薪资","薪资范围" + }; + /** + * 手动设置数据类型 0数字 1字符串 + */ + private static final Integer[] DATA_TYPE_COLUMNS = { + 0,1,1,0,0,1 + }; + + /** + * Excel sheet最大行数,默认65536 + */ + public static final int sheetSize = 65536; + + /** + * 工作表名称 + */ + private String sheetName; + + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Type type; + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 导入导出数据列表 + */ + private List list; + + /** + * 注解列表 + */ + private List fields; + + /** + * 实体对象 + */ + public Class clazz; + + public ExcelUtil(Class clazz) { + this.clazz = clazz; + } + + public void init(List list, String sheetName, Type type) { + if (list == null) { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + createExcelField(); + createWorkbook(); + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(InputStream is) throws Exception { + return importExcel(StringUtils.EMPTY, is); + } + + /** + * 对excel表单指定表格索引名转换成list + * + * @param sheetName 表格索引名 + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(String sheetName, InputStream is) throws Exception { + this.type = Type.IMPORT; + this.wb = WorkbookFactory.create(is); + List list = new ArrayList(); + Sheet sheet = null; + if (StringUtils.isNotEmpty(sheetName)) { + // 如果指定sheet名,则取指定sheet中的内容. + sheet = wb.getSheet(sheetName); + } else { + // 如果传入的sheet名不存在则默认指向第1个sheet. + sheet = wb.getSheetAt(0); + } + + if (sheet == null) { + throw new IOException("文件sheet不存在"); + } + + int rows = sheet.getPhysicalNumberOfRows(); + + if (rows > 0) { + // 定义一个map用于存放excel列的序号和field. + Map cellMap = new HashMap(); + // 获取表头 + Row heard = sheet.getRow(0); + + /** + * 检查导入的模板是否正确 + */ + if (!checkTemplate(heard)) { + System.out.println("模板错误,请检查列名是否正确"); + return null; + } + + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) { + Cell cell = heard.getCell(i); + if (cell != null) { + String value = this.getCellValue(heard, i).toString(); + cellMap.put(value, i); + } + else { + cellMap.put(null, i); + } + } + // 有数据时才处理 得到类的所有field. + Field[] allFields = clazz.getDeclaredFields(); + // 定义一个map用于存放列的序号和field. + Map fieldsMap = new HashMap(); + for (int col = 0; col < allFields.length; col++) { + Field field = allFields[col]; + Excel attr = field.getAnnotation(Excel.class); + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) { + // 设置类的私有字段属性可访问. + field.setAccessible(true); + Integer column = cellMap.get(attr.name()); + fieldsMap.put(column, field); + } + } + + /** + * 定义一个收集错误信息的集合 + */ + List errorMessages = new ArrayList<>(); + + for (int i = 1; i < rows; i++) { + // 从第2行开始取数据,默认第一行是表头. + Row row = sheet.getRow(i); + + /** + * 检查导入数据是否正确 + */ + int nums = row.getPhysicalNumberOfCells(); + for (int j = 0; j < nums; j++) { + if (!checkDataType(row,j)){ + String errorMessage = String.format("第%d行%d列数据类型错误", i + 1,j+1); + errorMessages.add(errorMessage); + } + } + + + T entity = null; + for (Map.Entry entry : fieldsMap.entrySet()) { + if (entry.getKey() == null){ + continue; + } + Object val = this.getCellValue(row, entry.getKey()); + + // 如果不存在实例则新建. + entity = (entity == null ? clazz.newInstance() : entity); + // 从map中得到对应列的field. + Field field = fieldsMap.get(entry.getKey()); + // 取得类型,并根据对象类型设置值. + Class fieldType = field.getType(); + if (String.class == fieldType) { + String s = Convert.toStr(val); + if (StringUtils.endsWith(s, ".0")) { + val = StringUtils.substringBefore(s, ".0"); + } else { + String dateFormat = field.getAnnotation(Excel.class).dateFormat(); + if (StringUtils.isNotEmpty(dateFormat)) { + val = DateUtils.parseDateToStr(dateFormat, (Date) val); + } else { + val = Convert.toStr(val); + } + } + } else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) { + val = Convert.toInt(val); + } else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) { + val = Convert.toLong(val); + } else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) { + val = Convert.toDouble(val); + } else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) { + val = Convert.toFloat(val); + } else if (BigDecimal.class == fieldType) { + val = Convert.toBigDecimal(val); + } else if (Date.class == fieldType) { + if (val instanceof String) { + val = DateUtils.parseDate(val); + } else if (val instanceof Double) { + val = DateUtil.getJavaDate((Double) val); + } + } + if (fieldType != null) { + Excel attr = field.getAnnotation(Excel.class); + String propertyName = field.getName(); + if (StringUtils.isNotEmpty(attr.targetAttr())) { + propertyName = field.getName() + "." + attr.targetAttr(); + } else if (StringUtils.isNotEmpty(attr.readConverterExp())) { + val = reverseByExp(String.valueOf(val), attr.readConverterExp()); + } + ReflectUtils.invokeSetter(entity, propertyName, val); + } + } + list.add(entity); + } + //打印所有错误信息 + System.out.println("-------------------------错误信息如下:--------------------------"); + for (String errorMessage : errorMessages) { + System.out.println(errorMessage); + } + } + + return list; + } + + /** + * 检查导入的模板 + * @param heard + * @return + */ + private boolean checkTemplate(Row heard) { + int numberOfCells = heard.getPhysicalNumberOfCells(); + if (numberOfCells!=TEMPLATE_COLUMNS.length){ + return false; + } + for (int i = 0; i < numberOfCells; i++) { + if (!heard.getCell(i).getStringCellValue().equals(TEMPLATE_COLUMNS[i])){ + return false; + } + } + return true; + } + + /** + * 设置数据类型做判断 + * @param row + * @return + */ + private boolean checkDataType(Row row,Integer column) { + try { + //设置数据类型 + + if (1==DATA_TYPE_COLUMNS[column]){ + String stringCellValue = row.getCell(column).getStringCellValue(); + }else { + /*String numericCellValue = row.getCell(column).getStringCellValue(); + double v = Double.parseDouble(numericCellValue);*/ + double numericCellValue = row.getCell(column).getNumericCellValue(); + } + return true; + } catch (Exception e) { + return false; + } + } + + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + * @throws IOException + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName){ + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(list, sheetName, Type.EXPORT); + writeSheet(); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public void exportExcel(HttpServletResponse response){ + try{ + wb.write(response.getOutputStream()); + } catch (Exception e){ + log.error("导出Excel异常{}", e.getMessage()); + } finally { + IOUtils.closeQuietly(wb); + } + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public String exportExcel(List list, String sheetName) { + this.init(list, sheetName, Type.EXPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public String importTemplateExcel(String sheetName) { + this.init(null, sheetName, Type.IMPORT); + return exportExcel(); + } + + /** + * 写入sheet数据 + */ + public void writeSheet(){ + // 取出一共有多少个sheet. + double sheetNo = Math.ceil(list.size() / sheetSize); + for (int index = 0; index <= sheetNo; index++) { + createSheet(sheetNo, index); + + // 产生一行 + Row row = sheet.createRow(0); + int column = 0; + // 写入各个字段的列头名称 + for (Object[] os : fields) { + Excel excel = (Excel) os[1]; + this.createCell(excel, row, column++); + } + if (Type.EXPORT.equals(type)) { + fillExcelData(index, row); + } + } + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public String exportExcel() { + OutputStream out = null; + try { + writeSheet(); + String filename = encodingFilename(sheetName); + out = new FileOutputStream(getAbsoluteFile(filename)); + wb.write(out); + return filename; + } catch (Exception e) { + log.error("导出Excel异常{}", e.getMessage()); + throw new PoiException("导出Excel失败,请联系管理员!"); + } finally { + try { + if (wb != null) { + wb.close(); + } + if (out != null) { + out.close(); + } + } catch (IOException e1) { + e1.printStackTrace(); + } + + } + } + + /** + * 填充excel数据 + * + * @param index 序号 + * @param row 单元格行 + */ + public void fillExcelData(int index, Row row) { + int startNo = index * sheetSize; + int endNo = Math.min(startNo + sheetSize, list.size()); + for (int i = startNo; i < endNo; i++) { + row = sheet.createRow(i + 1 - startNo); + // 得到导出对象. + T vo = (T) list.get(i); + int column = 0; + for (Object[] os : fields) { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + // 设置实体类私有属性可访问 + field.setAccessible(true); + this.addCell(excel, row, vo, field, column++); + } + } + } + + /** + * 创建表格样式 + * + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) { + // 写入各条记录,每条记录对应excel表中的一行 + Map styles = new HashMap(); + CellStyle style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + headerFont.setColor(IndexedColors.WHITE.getIndex()); + style.setFont(headerFont); + styles.put("header", style); + + return styles; + } + + /** + * 创建单元格 + */ + public Cell createCell(Excel attr, Row row, int column) { + // 创建列 + Cell cell = row.createCell(column); + // 写入列信息 + cell.setCellValue(attr.name()); + setDataValidation(attr, row, column); + cell.setCellStyle(styles.get("header")); + return cell; + } + + /** + * 设置单元格信息 + * + * @param value 单元格值 + * @param attr 注解相关 + * @param cell 单元格信息 + */ + public void setCellVo(Object value, Excel attr, Cell cell) { + if (Excel.ColumnType.STRING == attr.cellType()) { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(value == null ? attr.defaultValue() : value + attr.suffix()); + } else if (Excel.ColumnType.NUMERIC == attr.cellType()) { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(Integer.parseInt(value + "")); + } + } + + /** + * 创建表格样式 + */ + public void setDataValidation(Excel attr, Row row, int column) { + if (attr.name().indexOf("注:") >= 0) { + sheet.setColumnWidth(column, 6000); + } else { + // 设置列宽 + sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); + row.setHeight((short) (attr.height() * 20)); + } + // 如果设置了提示信息则鼠标放上去提示. + if (StringUtils.isNotEmpty(attr.prompt())) { + // 这里默认设了2-101列提示. + setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); + } + // 如果设置了combo属性则本列只能选择不能输入 + if (attr.combo().length > 0) { + // 这里默认设了2-101列只能选择不能输入. + setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); + } + } + + /** + * 添加单元格 + */ + public Cell addCell(Excel attr, Row row, T vo, Field field, int column) { + Cell cell = null; + try { + // 设置行高 + row.setHeight((short) (attr.height() * 20)); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) { + // 创建cell + cell = row.createCell(column); + cell.setCellStyle(styles.get("data")); + + // 用于读取对象中的属性 + Object value = getTargetValue(vo, field, attr); + //时间类型格式化 + String dateFormat = attr.dateFormat(); + //读取表达式 + String readConverterExp = attr.readConverterExp(); + //分隔符 + String splitStr = attr.splitStr(); + //反射对象 + Class invokeClass = attr.invokeClass(); + //反射方法名称 + String invokeMethod = attr.invokeMethod(); + if (StringUtils.isNotEmpty(dateFormat) && value != null) { + cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); + } else if (StringUtils.isNotEmpty(readConverterExp) && value != null) { + // 判断是否有分隔符 + if (StringUtils.isNotEmpty(splitStr)){ + StringBuilder cellValue = new StringBuilder(); + String valueStr = String.valueOf(value); + String[] valueStrSplit = valueStr.split(splitStr); + int valueStrSplitLength = valueStrSplit.length; + for (int i = 0; ; i++) { + cellValue.append(convertByExp(valueStrSplit[i], readConverterExp)); + if (i == valueStrSplitLength-1){ + break; + } + cellValue.append(","); + } + cell.setCellValue(cellValue.toString()); + } else { + cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp)); + } + + } + // 判断是否需要取值 + else if((!invokeClass.getName().equals(String.class.getName())) && StringUtils.isNotEmpty(invokeMethod)){ + Object bean = SpringUtils.getBean(invokeClass); + Method thisMethod = null; + Method[] methods = invokeClass.getMethods(); + for (Method method : methods) { + if (method.getName().equals(invokeMethod)){ + thisMethod = method; + continue; + } + } + cell.setCellValue(thisMethod.invoke(bean,value).toString()); + } else { + // 设置列类型 + setCellVo(value, attr, cell); + } + } + } catch (Exception e) { + log.error("导出Excel失败{}", e); + } + return cell; + } + + /** + * 设置 POI XSSFSheet 单元格提示 + * + * @param sheet 表单 + * @param promptTitle 提示标题 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + dataValidation.createPromptBox(promptTitle, promptContent); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } + + /** + * 设置某些列的值只能输入预制的数据,显示下拉框. + * + * @param sheet 要设置的sheet. + * @param textlist 下拉框显示的内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + * @return 设置好的sheet. + */ + public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) { + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 加载下拉列表内容 + DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, regions); + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @return 解析后值 + * @throws Exception + */ + public static String convertByExp(String propertyValue, String converterExp) throws Exception { + try { + String[] convertSource = converterExp.split(","); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (itemArray[0].equals(propertyValue)) { + return itemArray[1]; + } + } + } catch (Exception e) { + throw e; + } + return propertyValue; + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @return 解析后值 + * @throws Exception + */ + public static String reverseByExp(String propertyValue, String converterExp) throws Exception { + try { + String[] convertSource = converterExp.split(","); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (itemArray[1].equals(propertyValue)) { + return itemArray[0]; + } + } + } catch (Exception e) { + throw e; + } + return propertyValue; + } + + /** + * 编码文件名 + */ + public String encodingFilename(String filename) { + filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; + return filename; + } + + /** + * 获取下载路径 + * + * @param filename 文件名称 + */ + public String getAbsoluteFile(String filename) { + String downloadPath = System.getProperty("user.dir") + File.separator + filename; + File desc = new File(downloadPath); + if (!desc.getParentFile().exists()) { + desc.getParentFile().mkdirs(); + } + return downloadPath; + } + + /** + * 获取bean中的属性值 + * + * @param vo 实体对象 + * @param field 字段 + * @param excel 注解 + * @return 最终的属性值 + * @throws Exception + */ + private Object getTargetValue(T vo, Field field, Excel excel) throws Exception { + Object o = field.get(vo); + if (StringUtils.isNotEmpty(excel.targetAttr())) { + String target = excel.targetAttr(); + if (target.indexOf(".") > -1) { + String[] targets = target.split("[.]"); + for (String name : targets) { + o = getValue(o, name); + } + } else { + o = getValue(o, target); + } + } + return o; + } + + /** + * 以类的属性的get方法方法形式获取值 + * + * @param o + * @param name + * @return value + * @throws Exception + */ + private Object getValue(Object o, String name) throws Exception { + if (StringUtils.isNotEmpty(name)) { + Class clazz = o.getClass(); + String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1); + Method method = clazz.getMethod(methodName); + o = method.invoke(o); + } + return o; + } + + /** + * 得到所有定义字段 + */ + private void createExcelField() { + this.fields = new ArrayList<>(); + List tempFields = new ArrayList<>(); + tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); + tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); + for (Field field : tempFields) { + // 单注解 + if (field.isAnnotationPresent(Excel.class)) { + putToField(field, field.getAnnotation(Excel.class)); + } + + // 多注解 + if (field.isAnnotationPresent(Excels.class)) { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + for (Excel excel : excels) { + putToField(field, excel); + } + } + } + } + + /** + * 放到字段集合中 + */ + private void putToField(Field field, Excel attr) { + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) { + this.fields.add(new Object[] { field, attr }); + } + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook() { + this.wb = new SXSSFWorkbook(500); + } + + /** + * 创建工作表 + * + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet(double sheetNo, int index) { + this.sheet = wb.createSheet(); + this.styles = createStyles(wb); + // 设置工作表的名称. + if (sheetNo == 0) { + wb.setSheetName(index, sheetName); + } else { + wb.setSheetName(index, sheetName + index); + } + } + + /** + * 获取单元格值 + * + * @param row 获取的行 + * @param column 获取单元格列号 + * @return 单元格值 + */ + public Object getCellValue(Row row, int column) { + if (row == null) { + return row; + } + Object val = ""; + try { + Cell cell = row.getCell(column); + if (cell != null) { + if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA) { + val = cell.getNumericCellValue(); + if (HSSFDateUtil.isCellDateFormatted(cell)) { + val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 + } else { + if ((Double) val % 1 > 0) { + val = new DecimalFormat("0.00").format(val); + } else { + val = new DecimalFormat("0").format(val); + } + } + } else if (cell.getCellTypeEnum() == CellType.STRING) { + val = cell.getStringCellValue(); + } else if (cell.getCellTypeEnum() == CellType.BOOLEAN) { + val = cell.getBooleanCellValue(); + } else if (cell.getCellTypeEnum() == CellType.ERROR) { + val = cell.getErrorCellValue(); + } + + } + } catch (Exception e) { + return val; + } + return val; + } +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/poi/annotation/Excel.java b/bwie-common/src/main/java/com/bwie/common/utils/poi/annotation/Excel.java new file mode 100644 index 0000000..c2b29b9 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/poi/annotation/Excel.java @@ -0,0 +1,122 @@ +package com.bwie.common.utils.poi.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义导出Excel数据注解 + * + * @author + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Excel +{ + /** + * 导出到Excel中的名字. + */ + public String name() default ""; + + /** + * 日期格式, 如: yyyy-MM-dd + */ + public String dateFormat() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + public String readConverterExp() default ""; + + /** + * 分隔符 + */ + public String splitStr() default ""; + + /** + * 可执行的反射方法值为1个 + */ + public String invokeMethod() default ""; + + /** + * 可执行的反射类 从SpringIoc容器当中取值 + */ + public Class invokeClass() default String.class; + + /** + * 导出类型(0数字 1字符串) + */ + public ColumnType cellType() default ColumnType.STRING; + + /** + * 导出时在excel中每个列的高度 单位为字符 + */ + public double height() default 14; + + /** + * 导出时在excel中每个列的宽 单位为字符 + */ + public double width() default 16; + + /** + * 文字后缀,如% 90 变成90% + */ + public String suffix() default ""; + + /** + * 当值为空时,字段的默认值 + */ + public String defaultValue() default ""; + + /** + * 提示信息 + */ + public String prompt() default ""; + + /** + * 设置只能选择不能输入的列内容. + */ + public String[] combo() default {}; + + /** + * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. + */ + public boolean isExport() default true; + + /** + * 另一个类中的属性名称,支持多级获取,以小数点隔开 + */ + public String targetAttr() default ""; + + /** + * 字段类型(0:导出导入;1:仅导出;2:仅导入) + */ + Type type() default Type.ALL; + + public enum Type { + ALL(0), EXPORT(1), IMPORT(2); + private final int value; + + Type(int value) { + this.value = value; + } + + public int value() { + return this.value; + } + } + + public enum ColumnType { + NUMERIC(0), STRING(1); + private final int value; + + ColumnType(int value) { + this.value = value; + } + + public int value() { + return this.value; + } + } +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/poi/annotation/Excels.java b/bwie-common/src/main/java/com/bwie/common/utils/poi/annotation/Excels.java new file mode 100644 index 0000000..9760459 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/poi/annotation/Excels.java @@ -0,0 +1,18 @@ +package com.bwie.common.utils.poi.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Excel注解集 + * + * @author + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Excels +{ + Excel[] value(); +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/poi/exception/PoiException.java b/bwie-common/src/main/java/com/bwie/common/utils/poi/exception/PoiException.java new file mode 100644 index 0000000..a08fe9c --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/poi/exception/PoiException.java @@ -0,0 +1,27 @@ +package com.bwie.common.utils.poi.exception; + +/** + * 业务异常 + * + * @author + */ +public class PoiException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + protected final String message; + + public PoiException(String message) { + this.message = message; + } + + public PoiException(String message, Throwable e) { + super(message, e); + this.message = message; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/poi3/CustomCellStyle.java b/bwie-common/src/main/java/com/bwie/common/utils/poi3/CustomCellStyle.java new file mode 100644 index 0000000..c3f36b1 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/poi3/CustomCellStyle.java @@ -0,0 +1,79 @@ +package com.bwie.common.utils.poi3; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +import org.apache.poi.ss.usermodel.*; + +import java.util.List; + +public class CustomCellStyle implements CellWriteHandler { + + + @Override + public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + + + } + + @Override + public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + //获取工作簿 + Workbook workbook = writeSheetHolder.getSheet().getWorkbook(); + + //获取单元格样式 + CellStyle cellStyle = workbook.createCellStyle(); + + //判断非首行 + if(!isHead && cell.getColumnIndex()==2){ + + String stringCellValue = cell.getStringCellValue(); + + //double numericCellValue = cell.getNumericCellValue(); + if("女".equals(stringCellValue)){ + //填充背景色 + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + cellStyle.setFillForegroundColor(IndexedColors.RED.index); + + //设置字体 + Font font = workbook.createFont(); + font.setBold(true); + font.setColor(IndexedColors.BLACK.getIndex()); + cellStyle.setFont(font); + } + + + }else{} + + //设置边框 + cellStyle.setBorderTop(BorderStyle.THIN); + cellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); + + cellStyle.setBorderRight(BorderStyle.THIN); + cellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); + + cellStyle.setBorderBottom(BorderStyle.THIN); + cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); + + cellStyle.setBorderLeft(BorderStyle.THIN); + cellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); + + cell.setCellStyle(cellStyle); + + } +} diff --git a/bwie-common/src/main/java/com/bwie/common/utils/poi3/EasyExcelUtil.java b/bwie-common/src/main/java/com/bwie/common/utils/poi3/EasyExcelUtil.java new file mode 100644 index 0000000..d609f86 --- /dev/null +++ b/bwie-common/src/main/java/com/bwie/common/utils/poi3/EasyExcelUtil.java @@ -0,0 +1,208 @@ +//package com.bwie.common.utils.poi3; +// +//import com.alibaba.excel.EasyExcel; +//import com.alibaba.excel.ExcelWriter; +//import com.alibaba.excel.metadata.Head; +//import com.alibaba.excel.support.ExcelTypeEnum; +//import com.alibaba.excel.util.CollectionUtils; +//import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +//import com.alibaba.excel.write.merge.AbstractMergeStrategy; +//import com.alibaba.excel.write.metadata.WriteSheet; +//import com.alibaba.excel.write.metadata.style.WriteCellStyle; +//import com.alibaba.excel.write.metadata.style.WriteFont; +//import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +//import lombok.Data; +//import lombok.NoArgsConstructor; +//import org.apache.poi.ss.formula.functions.T; +//import org.apache.poi.ss.usermodel.Cell; +//import org.apache.poi.ss.usermodel.FillPatternType; +//import org.apache.poi.ss.usermodel.IndexedColors; +//import org.apache.poi.ss.usermodel.Sheet; +//import org.apache.poi.ss.util.CellRangeAddress; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Component; +// +//import javax.security.sasl.SaslServer; +//import javax.servlet.http.HttpServletResponse; +//import java.io.IOException; +//import java.io.UnsupportedEncodingException; +//import java.net.URLEncoder; +//import java.util.ArrayList; +//import java.util.Arrays; +//import java.util.List; +//import java.util.stream.Collectors; +// +//// 自定义合并策略 该类继承了AbstractMergeStrategy抽象合并策略,需要重写merge()方法 +//@Component +//@Data +//@NoArgsConstructor +//public class EasyExcelUtil extends AbstractMergeStrategy { +// +// +// @Autowired +// private SaslServer saslServer; +// +// /** +// * 分组,每几行合并一次 +// */ +// private List exportFieldGroupCountList; +// +// /** +// * 目标合并列index +// */ +// private Integer targetColumnIndex; +// +// // 需要开始合并单元格的首行index +// private Integer rowIndex; +// +// // exportDataList为待合并目标列的值 +// public EasyExcelUtil(List exportDataList, Integer targetColumnIndex) { +// this.exportFieldGroupCountList = getGroupCountList(exportDataList); +// this.targetColumnIndex = targetColumnIndex; +// } +// +// +// @Override +// protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { +// +// if (null == rowIndex) { +// rowIndex = cell.getRowIndex(); +// } +// // 仅从首行以及目标列的单元格开始合并,忽略其他 +// if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) { +// mergeGroupColumn(sheet); +// } +// } +// +// private void mergeGroupColumn(Sheet sheet) { +// int rowCount = rowIndex; +// for (Integer count : exportFieldGroupCountList) { +// if(count == 1) { +// rowCount += count; +// continue ; +// } +// // 合并单元格 +// CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex); +// sheet.addMergedRegionUnsafe(cellRangeAddress); +// rowCount += count; +// } +// } +// +// // 该方法将目标列根据值是否相同连续可合并,存储可合并的行数 +// private List getGroupCountList(List exportDataList){ +// if (CollectionUtils.isEmpty(exportDataList)) { +// return new ArrayList<>(); +// } +// +// List groupCountList = new ArrayList<>(); +// int count = 1; +// +// for (int i = 1; i < exportDataList.size(); i++) { +// if (exportDataList.get(i).equals(exportDataList.get(i - 1))) { +// count++; +// } else { +// groupCountList.add(count); +// count = 1; +// } +// } +// // 处理完最后一条后 +// groupCountList.add(count); +// return groupCountList; +// } +// +// +// // 修改WriteSheet的代码如下 +// public void writeExcel(HttpServletResponse response,String fileName,Integer mergeIndex,String firstTitle,String [] secondTile,Integer sheetSize) { +// // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman +// response.setContentType("application/vnd.ms-excel"); +// response.setCharacterEncoding("utf-8"); +// // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 +// try { +// String name = URLEncoder.encode(fileName, "UTF-8"); +// +// response.setHeader("Content-disposition", "attachment;filename=" + name + ".xlsx"); +// +// List> heads = new ArrayList<>(); +// for (int i = 0; i < secondTile.length; i++) { +// heads.add(Arrays.asList(firstTitle,secondTile[i])); +// } +// +// +// +// +// ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()) +// .build(); +// +// List studentListAll = studentService.findStudentListAll(); +// //select * from t_student limit 0,2 1 (pageNum-1)*pageSize +// //select * from t_student limit 2,2 2 +// //select * from t_student limit 4,2 3 +// //select * from t_student limit 6,2 4 +// +// Integer count = studentListAll.size(); +// Integer sheets = (int)Math.ceil((double)count/sheetSize); +// +// +// +// for (int i = 0; i < sheets; i++) { +// PageInfo studentList = studentService.findStudentList(i + 1, sheetSize); +// WriteSheet sheet1 = EasyExcel.writerSheet(i, "模版"+(i+1)).head(Student.class) +// .head(heads).registerWriteHandler(new EasyExcelUtil(studentList.getList().stream().map(Student::getSex).collect(Collectors.toList()), mergeIndex)) +// .registerWriteHandler(new CustomCellStyle()).build(); +// +// +// excelWriter.write(studentList.getList(),sheet1); +// } +// +// +// excelWriter.finish(); +// response.flushBuffer(); +// +// +// +// +// +// } catch (UnsupportedEncodingException e) { +// e.printStackTrace(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// +// } +// +// +// // 修改WriteSheet的代码如下 +// public void writeExcel(HttpServletResponse response,String fileName, List list,String [] secondTile) { +// // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman +// response.setContentType("application/vnd.ms-excel"); +// response.setCharacterEncoding("utf-8"); +// // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 +// try { +// String name = URLEncoder.encode(fileName, "UTF-8"); +// +// response.setHeader("Content-disposition", "attachment;filename=" + name + ".xlsx"); +// +// List> heads = new ArrayList<>(); +// for (int i = 0; i < secondTile.length; i++) { +// heads.add(Arrays.asList(secondTile[i])); +// } +// +// +// EasyExcel.write(response.getOutputStream(),Student.class).sheet("模板").head(Student.class) +// .head(heads) +// //.registerWriteHandler(new EasyExcelUtil(list.stream().map(Student::getName).collect(Collectors.toList()), mergeIndex)) +// //.registerWriteHandler(new CustomCellStyle()) //设置单元格颜色样式 +// .doWrite(list); +// +// +// } catch (UnsupportedEncodingException e) { +// e.printStackTrace(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// +// } +// +// +// +//} \ No newline at end of file diff --git a/bwie-gateway/pom.xml b/bwie-gateway/pom.xml index 3c4d2fc..3015468 100644 --- a/bwie-gateway/pom.xml +++ b/bwie-gateway/pom.xml @@ -17,7 +17,6 @@ UTF-8 - @@ -42,5 +41,4 @@ - diff --git a/bwie-gateway/src/main/java/com/bwie/gateway/filters/AuthFilter.java b/bwie-gateway/src/main/java/com/bwie/gateway/filters/AuthFilter.java index 483141b..b570369 100644 --- a/bwie-gateway/src/main/java/com/bwie/gateway/filters/AuthFilter.java +++ b/bwie-gateway/src/main/java/com/bwie/gateway/filters/AuthFilter.java @@ -1,85 +1,85 @@ -package com.bwie.gateway.filters; - -import com.bwie.common.constants.TokenConstants; -import com.bwie.common.utils.JwtUtils; -import com.bwie.common.utils.StringUtils; -import com.bwie.gateway.config.IgnoreWhiteConfig; -import com.bwie.gateway.utils.GatewayUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.http.HttpStatus; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; - -import java.util.List; - -/** - * @ClassName: - * @Description: 鉴权过滤器 - * @Author: zhuwenqiang - * @Date: 2023/8/18 - */ -@Component -public class AuthFilter implements GlobalFilter, Ordered { - - @Autowired - private IgnoreWhiteConfig ignoreWhiteConfig; - - @Autowired - private RedisTemplate redisTemplate; - - /** - * 过滤方法 验证 token - * @param exchange 请求的上下文 通过这个参数 可以获取到 请求对象 以及 响应对象 - * @param chain 网关过滤器链 chain 放行 或者 拦截 - * @return Mono - */ - @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - // 验证当前的请求 是否需要拦截 【配置白名单请求 不拦截的请求 】 将白名单请求配置到配置文件中 - // 获取系统白名单请求 - List whites = ignoreWhiteConfig.getWhites(); - // 获取当前的请求 URI - ServerHttpRequest request = exchange.getRequest(); - String path = request.getURI().getPath(); - boolean matches = StringUtils.matches(path, whites); - if (matches) { // 放行 - return chain.filter(exchange); - } - // 获取token - String token = request.getHeaders().getFirst(TokenConstants.TOKEN); - // token 非空验证 - if (StringUtils.isEmpty(token)) { - // 不放行 提示错误信息 - return GatewayUtils.errorResponse(exchange, "token不能为空!", HttpStatus.UNAUTHORIZED); - } - try { - // token 合法性性 - JwtUtils.parseToken(token); - } catch (Exception ex) { - return GatewayUtils.errorResponse(exchange, "token格式错误!"); - } - // token 是否过期 - // 获取 UserKey - String userKey = JwtUtils.getUserKey(token); - if (!redisTemplate.hasKey(TokenConstants.LOGIN_TOKEN_KEY + userKey)) { - return GatewayUtils.errorResponse(exchange, "token过期!"); - } - // 放行 - return chain.filter(exchange); - } - - /** - * 当存在多个filter的时候 用来执行执行的优先级 - * @return 数字 数字的值越小 执行的优先级越高 - */ - @Override - public int getOrder() { - return 0; - } -} +//package com.bwie.gateway.filters; +// +//import com.bwie.common.constants.TokenConstants; +//import com.bwie.common.utils.JwtUtils; +//import com.bwie.common.utils.StringUtils; +//import com.bwie.gateway.config.IgnoreWhiteConfig; +//import com.bwie.gateway.utils.GatewayUtils; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.cloud.gateway.filter.GatewayFilterChain; +//import org.springframework.cloud.gateway.filter.GlobalFilter; +//import org.springframework.core.Ordered; +//import org.springframework.data.redis.core.RedisTemplate; +//import org.springframework.http.HttpStatus; +//import org.springframework.http.server.reactive.ServerHttpRequest; +//import org.springframework.stereotype.Component; +//import org.springframework.web.server.ServerWebExchange; +//import reactor.core.publisher.Mono; +// +//import java.util.List; +// +///** +// * @ClassName: +// * @Description: 鉴权过滤器 +// * @Author: zhuwenqiang +// * @Date: 2023/8/18 +// */ +//@Component +//public class AuthFilter implements GlobalFilter, Ordered { +// +// @Autowired +// private IgnoreWhiteConfig ignoreWhiteConfig; +// +// @Autowired +// private RedisTemplate redisTemplate; +// +// /** +// * 过滤方法 验证 token +// * @param exchange 请求的上下文 通过这个参数 可以获取到 请求对象 以及 响应对象 +// * @param chain 网关过滤器链 chain 放行 或者 拦截 +// * @return Mono +// */ +// @Override +// public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { +// // 验证当前的请求 是否需要拦截 【配置白名单请求 不拦截的请求 】 将白名单请求配置到配置文件中 +// // 获取系统白名单请求 +// List whites = ignoreWhiteConfig.getWhites(); +// // 获取当前的请求 URI +// ServerHttpRequest request = exchange.getRequest(); +// String path = request.getURI().getPath(); +// boolean matches = StringUtils.matches(path, whites); +// if (matches) { // 放行 +// return chain.filter(exchange); +// } +// // 获取token +// String token = request.getHeaders().getFirst(TokenConstants.TOKEN); +// // token 非空验证 +// if (StringUtils.isEmpty(token)) { +// // 不放行 提示错误信息 +// return GatewayUtils.errorResponse(exchange, "token不能为空!", HttpStatus.UNAUTHORIZED); +// } +// try { +// // token 合法性性 +// JwtUtils.parseToken(token); +// } catch (Exception ex) { +// return GatewayUtils.errorResponse(exchange, "token格式错误!"); +// } +// // token 是否过期 +// // 获取 UserKey +// String userKey = JwtUtils.getUserKey(token); +// if (!redisTemplate.hasKey(TokenConstants.LOGIN_TOKEN_KEY + userKey)) { +// return GatewayUtils.errorResponse(exchange, "token过期!"); +// } +// // 放行 +// return chain.filter(exchange); +// } +// +// /** +// * 当存在多个filter的时候 用来执行执行的优先级 +// * @return 数字 数字的值越小 执行的优先级越高 +// */ +// @Override +// public int getOrder() { +// return 0; +// } +//} diff --git a/bwie-models/bwie-sell/.gitignore b/bwie-models/bwie-sell/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/bwie-models/bwie-sell/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/bwie-models/bwie-sell/pom.xml b/bwie-models/bwie-sell/pom.xml new file mode 100644 index 0000000..cb0f70a --- /dev/null +++ b/bwie-models/bwie-sell/pom.xml @@ -0,0 +1,90 @@ + + + 4.0.0 + + com.bwie + bwie-models + 1.0-SNAPSHOT + + + bwie-sell + + + 8 + 8 + UTF-8 + + + + + com.bwie + bwie-common + + + + org.springframework.boot + spring-boot-starter-web + + + + com.alibaba + druid-spring-boot-starter + 1.2.8 + + + + mysql + mysql-connector-java + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.2.2 + + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.4.1 + + + + org.springframework.boot + spring-boot-starter-test + test + + + com.github.tobato + fastdfs-client + 1.26.5 + + + + + + org.apache.poi + poi-ooxml + 3.17 + + + org.apache.poi + poi-ooxml-schemas + 3.17 + + + org.apache.commons + commons-lang3 + 3.12.0 + + + + + com.alibaba + easyexcel + 2.2.7 + + + \ No newline at end of file diff --git a/bwie-models/bwie-sell/src/main/java/com/bwie/sell/SellApplication.java b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/SellApplication.java new file mode 100644 index 0000000..acbdd0b --- /dev/null +++ b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/SellApplication.java @@ -0,0 +1,16 @@ +package com.bwie.sell; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author 86175 + */ +@SpringBootApplication +public class SellApplication { + + public static void main(String[] args) { + SpringApplication.run(SellApplication.class,args); + } + +} diff --git a/bwie-models/bwie-sell/src/main/java/com/bwie/sell/controller/SellController.java b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/controller/SellController.java new file mode 100644 index 0000000..26bf7c1 --- /dev/null +++ b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/controller/SellController.java @@ -0,0 +1,73 @@ +package com.bwie.sell.controller; + +import com.alibaba.fastjson.JSON; +import com.bwie.common.pojo.Sell; +import com.bwie.common.result.Result; +import com.bwie.sell.service.SellService; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +import static org.bouncycastle.asn1.cmc.CMCStatus.success; + +/** + * @author 86175 + */ +@RestController +@RequestMapping("/sell") +@Log4j2 +public class SellController { + + @Autowired + public SellService sellService; + @Autowired + public HttpServletRequest request; + + + /** + * 商品销售统计 + * 查出每台售货机卖的 + */ + @PostMapping("/shopStatistics") + public Result> listResult (){ + + log.info("功能描述:销售日志统计,请求URI:{},请求方式:{}",request.getServletPath(),request.getMethod()); + List sell=sellService.list(); + Result> success = Result.success(sell); + log.info("功能描述:销售日志统计,请求URI:{},请求方式:{},响应结果:{}",request.getServletPath(),request.getMethod(), JSON.toJSONString(success)); + return success; + } + /** + * 销售统计表展示 + */ + @PostMapping("/salesStatistics") + public Result> salesStatistics (){ + + log.info("功能描述:销售金额统计,请求URI:{},请求方式:{}",request.getServletPath(),request.getMethod()); + List sell=sellService.sellList(); + Result> success = Result.success(sell); + log.info("功能描述:销售金额统计,请求URI:{},请求方式:{},响应结果:{}",request.getServletPath(),request.getMethod(), JSON.toJSONString(success)); + return success; + } + + /** + * 商品销售统计导出 + */ + @PostMapping("/exportSell") + public Result exportSell(HttpServletResponse response){ +// Result success = + //先查询数据 + System.out.println(response); + log.info("功能描述:销售导出查询,请求URI:{},请求方式:{},请求参数{}",request.getServletPath(),request.getMethod(),response); + Result success =sellService.exportSell(response); + log.info("功能描述:销售导出查询,请求URI:{},请求方式:{},响应结果:{}",request.getServletPath(),request.getMethod(), JSON.toJSONString(success)); + return success; + + } +} diff --git a/bwie-models/bwie-sell/src/main/java/com/bwie/sell/mapper/SellMapper.java b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/mapper/SellMapper.java new file mode 100644 index 0000000..c386a71 --- /dev/null +++ b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/mapper/SellMapper.java @@ -0,0 +1,28 @@ +package com.bwie.sell.mapper; + +import com.bwie.common.pojo.Sell; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @author 86175 + */ +@Mapper +public interface SellMapper { + + /** + * 商品销售统计 + * @return + */ + List shopList(); + + /** + * 商品售价统计 + * @return + */ + List sellList(); + + + +} diff --git a/bwie-models/bwie-sell/src/main/java/com/bwie/sell/service/SellService.java b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/service/SellService.java new file mode 100644 index 0000000..94dc785 --- /dev/null +++ b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/service/SellService.java @@ -0,0 +1,29 @@ +package com.bwie.sell.service; + +import com.bwie.common.pojo.Sell; +import com.bwie.common.result.Result; +import com.github.pagehelper.PageInfo; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * @author 86175 + */ +public interface SellService { + + List list(); + + + List sellList(); + + + Result exportSell(HttpServletResponse response); + + + List findStudentListAll(); + + + PageInfo findStudentList(int i, Integer sheetSize); + +} diff --git a/bwie-models/bwie-sell/src/main/java/com/bwie/sell/service/impl/SellServiceImpl.java b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/service/impl/SellServiceImpl.java new file mode 100644 index 0000000..909f822 --- /dev/null +++ b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/service/impl/SellServiceImpl.java @@ -0,0 +1,68 @@ +package com.bwie.sell.service.impl; + +import com.bwie.common.pojo.Sell; +import com.bwie.common.result.Result; +import com.bwie.common.utils.poi.ExcelUtil; +import com.bwie.sell.mapper.SellMapper; +import com.bwie.sell.service.SellService; +import com.bwie.sell.util.poi3.EasyExcelUtil; +import com.github.pagehelper.PageInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * @author 86175 + */ +@Service +public class SellServiceImpl implements SellService { + + @Autowired + public SellMapper sellMapper; + + @Autowired + public EasyExcelUtil easyExcelUtil; + + + @Override + public List list() { + return sellMapper.shopList(); + } + + @Override + public List sellList() { + return sellMapper.sellList(); + } + + @Override + public Result exportSell(HttpServletResponse response) { + + List sells = sellMapper.sellList(); + //是以流的方式把数据传给用户 + ExcelUtil sellExcelUtil = new ExcelUtil<>(Sell.class); + /** + * sellExcelUtil 对象中的导出的方法 中第一次参数的是: + * 响应对象 + * 第二个参数是: + * 查询到的list集合 + * 第三个参数是: + * sheet名称 + * + */ + String s = sellExcelUtil.exportExcel(sells, "商品销售统计"); +// return Result.success(); + return Result.success(s); + } + + @Override + public List findStudentListAll() { + return null; + } + + @Override + public PageInfo findStudentList(int i, Integer sheetSize) { + return null; + } +} diff --git a/bwie-models/bwie-sell/src/main/java/com/bwie/sell/util/FastUtil.java b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/util/FastUtil.java new file mode 100644 index 0000000..7660d2b --- /dev/null +++ b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/util/FastUtil.java @@ -0,0 +1,55 @@ +package com.bwie.sell.util; + +import org.springframework.stereotype.Component; +import com.github.tobato.fastdfs.domain.fdfs.StorePath; +import com.github.tobato.fastdfs.service.FastFileStorageClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; + +/** + * @BelongsProject: 0107day02 + * @BelongsPackage: com.bw.config + * @Author: zhupengfei + * @CreateTime: 2023-02-01 08:52 + */ +@Component +public class FastUtil { + private static final Logger log = LoggerFactory.getLogger(FastUtil.class); + + @Resource + private FastFileStorageClient storageClient ; + + /** + * 上传文件 + */ + public String upload(MultipartFile multipartFile) throws Exception{ + String originalFilename = multipartFile.getOriginalFilename(). + substring(multipartFile.getOriginalFilename(). + lastIndexOf(".") + 1); + StorePath storePath = this.storageClient.uploadImageAndCrtThumbImage( + multipartFile.getInputStream(), + multipartFile.getSize(),originalFilename , null); + return storePath.getFullPath() ; + } + /** + * 删除文件 + */ + public String deleteFile(String fileUrl) { + if (StringUtils.isEmpty(fileUrl)) { + log.info("fileUrl == >>文件路径为空..."); + return "文件路径不能为空"; + } + try { + StorePath storePath = StorePath.parseFromUrl(fileUrl); + storageClient.deleteFile(storePath.getGroup(), storePath.getPath()); + } catch (Exception e) { + log.error(e.getMessage()); + } + return "删除成功"; + } + +} diff --git a/bwie-models/bwie-sell/src/main/java/com/bwie/sell/util/poi3/CustomCellStyle.java b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/util/poi3/CustomCellStyle.java new file mode 100644 index 0000000..5ed74d9 --- /dev/null +++ b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/util/poi3/CustomCellStyle.java @@ -0,0 +1,76 @@ +package com.bwie.sell.util.poi3; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import org.apache.poi.ss.usermodel.*; + +import java.util.List; + +public class CustomCellStyle implements CellWriteHandler { + + + @Override + public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + + + } + + @Override + public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + //获取工作簿 + Workbook workbook = writeSheetHolder.getSheet().getWorkbook(); + + //获取单元格样式 + CellStyle cellStyle = workbook.createCellStyle(); + + //判断非首行 + if(!isHead && cell.getColumnIndex()==2){ + + String stringCellValue = cell.getStringCellValue(); + + //double numericCellValue = cell.getNumericCellValue(); + if("女".equals(stringCellValue)){ + //填充背景色 + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + cellStyle.setFillForegroundColor(IndexedColors.RED.index); + + //设置字体 + Font font = workbook.createFont(); + font.setBold(true); + font.setColor(IndexedColors.BLACK.getIndex()); + cellStyle.setFont(font); + } + + + }else{} + + //设置边框 + cellStyle.setBorderTop(BorderStyle.THIN); + cellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); + + cellStyle.setBorderRight(BorderStyle.THIN); + cellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); + + cellStyle.setBorderBottom(BorderStyle.THIN); + cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); + + cellStyle.setBorderLeft(BorderStyle.THIN); + cellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); + + cell.setCellStyle(cellStyle); + + } +} diff --git a/bwie-models/bwie-sell/src/main/java/com/bwie/sell/util/poi3/EasyExcelUtil.java b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/util/poi3/EasyExcelUtil.java new file mode 100644 index 0000000..4a122ed --- /dev/null +++ b/bwie-models/bwie-sell/src/main/java/com/bwie/sell/util/poi3/EasyExcelUtil.java @@ -0,0 +1,193 @@ +package com.bwie.sell.util.poi3; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.util.CollectionUtils; +import com.alibaba.excel.write.merge.AbstractMergeStrategy; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.bwie.common.pojo.Sell; +import com.bwie.sell.service.SellService; +import com.github.pagehelper.PageInfo; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.security.sasl.SaslServer; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +// 自定义合并策略 该类继承了AbstractMergeStrategy抽象合并策略,需要重写merge()方法 +@Component +@Data +@NoArgsConstructor +public class EasyExcelUtil extends AbstractMergeStrategy { + + + @Autowired + private SellService sellService; + + /** + * 分组,每几行合并一次 + */ + private List exportFieldGroupCountList; + + /** + * 目标合并列index + */ + private Integer targetColumnIndex; + + // 需要开始合并单元格的首行index + private Integer rowIndex; + + // exportDataList为待合并目标列的值 + public EasyExcelUtil(List exportDataList, Integer targetColumnIndex) { + this.exportFieldGroupCountList = getGroupCountList(exportDataList); + this.targetColumnIndex = targetColumnIndex; + } + + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + + if (null == rowIndex) { + rowIndex = cell.getRowIndex(); + } + // 仅从首行以及目标列的单元格开始合并,忽略其他 + if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) { + mergeGroupColumn(sheet); + } + } + + private void mergeGroupColumn(Sheet sheet) { + int rowCount = rowIndex; + for (Integer count : exportFieldGroupCountList) { + if(count == 1) { + rowCount += count; + continue ; + } + // 合并单元格 + CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex); + sheet.addMergedRegionUnsafe(cellRangeAddress); + rowCount += count; + } + } + + // 该方法将目标列根据值是否相同连续可合并,存储可合并的行数 + private List getGroupCountList(List exportDataList){ + if (CollectionUtils.isEmpty(exportDataList)) { + return new ArrayList<>(); + } + + List groupCountList = new ArrayList<>(); + int count = 1; + + for (int i = 1; i < exportDataList.size(); i++) { + if (exportDataList.get(i).equals(exportDataList.get(i - 1))) { + count++; + } else { + groupCountList.add(count); + count = 1; + } + } + // 处理完最后一条后 + groupCountList.add(count); + return groupCountList; + } + + + // 修改WriteSheet的代码如下 + public void writeExcel(HttpServletResponse response,String fileName,Integer mergeIndex,String firstTitle,String [] secondTile,Integer sheetSize) { + // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 + try { + String name = URLEncoder.encode(fileName, "UTF-8"); + + response.setHeader("Content-disposition", "attachment;filename=" + name + ".xlsx"); + + List> heads = new ArrayList<>(); + for (int i = 0; i < secondTile.length; i++) { + heads.add(Arrays.asList(firstTitle,secondTile[i])); + } + + + ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()) + .build(); + + List studentListAll = sellService.findStudentListAll(); + //select * from t_student limit 0,2 1 (pageNum-1)*pageSize + //select * from t_student limit 2,2 2 + //select * from t_student limit 4,2 3 + //select * from t_student limit 6,2 4 + + Integer count = studentListAll.size(); + Integer sheets = (int)Math.ceil((double)count/sheetSize); + + for (int i = 0; i < sheets; i++) { + PageInfo studentList = sellService.findStudentList(i + 1, sheetSize); + WriteSheet sheet1 = EasyExcel.writerSheet(i, "模版"+(i+1)).head(Sell.class) + .head(heads).registerWriteHandler(new EasyExcelUtil(studentList.getList().stream().map(Sell::getPhone).collect(Collectors.toList()), mergeIndex)) + .registerWriteHandler(new CustomCellStyle()).build(); + + + excelWriter.write(studentList.getList(),sheet1); + } + excelWriter.finish(); + response.flushBuffer(); + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + + // 修改WriteSheet的代码如下 + public void writeExcel(HttpServletResponse response,String fileName, List list,String [] secondTile) { + // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 + try { + String name = URLEncoder.encode(fileName, "UTF-8"); + + response.setHeader("Content-disposition", "attachment;filename=" + name + ".xlsx"); + + List> heads = new ArrayList<>(); + for (int i = 0; i < secondTile.length; i++) { + heads.add(Arrays.asList(secondTile[i])); + } + + + EasyExcel.write(response.getOutputStream(),Sell.class).sheet("模板").head(Sell.class) + .head(heads) + //.registerWriteHandler(new EasyExcelUtil(list.stream().map(Student::getName).collect(Collectors.toList()), mergeIndex)) + //.registerWriteHandler(new CustomCellStyle()) //设置单元格颜色样式 + .doWrite(list); + + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + + +} \ No newline at end of file diff --git a/bwie-models/bwie-sell/src/main/resources/bootstrap.yml b/bwie-models/bwie-sell/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..45b0ad8 --- /dev/null +++ b/bwie-models/bwie-sell/src/main/resources/bootstrap.yml @@ -0,0 +1,58 @@ +# Tomcat +server: + port: 9004 +# Spring +spring: + rabbitmq: + host: 111.229.234.119 + port: 5672 + userName: guest + password: guest + listener: + simple: + prefetch: 1 + publisher-confirm-type: correlated + publisher-returns: true + main: + allow-circular-references: true + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + application: + # 应用名称 + name: bwie-sell + profiles: + # 环境配置 + active: dev + cloud: + sentinel: + transport: + # 控制台地址 + #sentinel 地址不需要改动 + dashboard: 127.0.0.1:8080 + # 指定sentinel控制台获取应用数据的端口,被占用会端口号默认 +1 + port: 8719 + nacos: + discovery: + # 服务注册地址 + server-addr: 111.229.234.119:8848 + config: + # 配置中心地址 + server-addr: 111.229.234.119:8848 + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} +fdfs: + so-timeout: 1500 # socket 连接时长 + connect-timeout: 600 # 连接 tracker 服务器超时时长 + # 这两个是你服务器的 IP 地址,注意 23000 端口也要打开,阿里云服务器记得配置安全组。tracker 要和 stroage 服务进行交流 + tracker-list: 111.229.234.119:22122 + web-server-url: 111.229.234.119:8888 + pool: + jmx-enabled: false + # 生成缩略图 + thumb-image: + height: 500 + width: 500 diff --git a/bwie-models/bwie-sell/src/main/resources/mapper/SellMapper.xml b/bwie-models/bwie-sell/src/main/resources/mapper/SellMapper.xml new file mode 100644 index 0000000..bab949b --- /dev/null +++ b/bwie-models/bwie-sell/src/main/resources/mapper/SellMapper.xml @@ -0,0 +1,59 @@ + + + + + + + diff --git a/bwie-models/bwie-user/src/main/resources/bootstrap.yml b/bwie-models/bwie-user/src/main/resources/bootstrap.yml index 3099172..f75fc4c 100644 --- a/bwie-models/bwie-user/src/main/resources/bootstrap.yml +++ b/bwie-models/bwie-user/src/main/resources/bootstrap.yml @@ -1,6 +1,6 @@ # Tomcat server: - port: 9004 + port: 9002 # Spring spring: rabbitmq: diff --git a/bwie-models/pom.xml b/bwie-models/pom.xml index 69c26c3..2a92926 100644 --- a/bwie-models/pom.xml +++ b/bwie-models/pom.xml @@ -13,6 +13,7 @@ pom bwie-user + bwie-sell diff --git a/f95ab62a-c2f3-4314-a2e6-ea20f916ad3c_商品销售统计.xlsx b/f95ab62a-c2f3-4314-a2e6-ea20f916ad3c_商品销售统计.xlsx new file mode 100644 index 0000000..a58c658 Binary files /dev/null and b/f95ab62a-c2f3-4314-a2e6-ea20f916ad3c_商品销售统计.xlsx differ