diff --git a/crmeb/.gitignore b/crmeb/.gitignore
new file mode 100644
index 0000000..c6fc819
--- /dev/null
+++ b/crmeb/.gitignore
@@ -0,0 +1,47 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
+
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+
+### VS Code ###
+.vscode/
+/crmeb_log/log_debug.log
+/crmeb_log/log_error.log
+/crmeb_log/log_info.log
+/crmeb_log/log_warn.log
+/crmeb_log/
+/.idea/
+src/main/java/com/zbkj/.DS_Store
+src/main/java/com/.DS_Store
+src/main/java/.DS_Store
+src/main/.DS_Store
+.DS_Store
+
+
+
+xx
\ No newline at end of file
diff --git a/crmeb/.mvn/wrapper/MavenWrapperDownloader.java b/crmeb/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..a45eb6b
--- /dev/null
+++ b/crmeb/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+ private static final String WRAPPER_VERSION = "0.5.6";
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+ * use instead of the default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+ ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH =
+ ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main(String args[]) {
+ System.out.println("- Downloader started");
+ File baseDirectory = new File(args[0]);
+ System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+ String url = DEFAULT_DOWNLOAD_URL;
+ if (mavenWrapperPropertyFile.exists()) {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try {
+ mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+ url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+ } catch (IOException e) {
+ System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+ } finally {
+ try {
+ if (mavenWrapperPropertyFileInputStream != null) {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println("- Downloading from: " + url);
+
+ File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+ if (!outputFile.getParentFile().exists()) {
+ if (!outputFile.getParentFile().mkdirs()) {
+ System.out.println(
+ "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+ }
+ }
+ System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+ try {
+ downloadFileFromURL(url, outputFile);
+ System.out.println("Done");
+ System.exit(0);
+ } catch (Throwable e) {
+ System.out.println("- Error downloading");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+ if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+ String username = System.getenv("MVNW_USERNAME");
+ char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+ Authenticator.setDefault(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(username, password);
+ }
+ });
+ }
+ URL website = new URL(urlString);
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel(website.openStream());
+ FileOutputStream fos = new FileOutputStream(destination);
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ fos.close();
+ rbc.close();
+ }
+
+}
diff --git a/crmeb/.mvn/wrapper/maven-wrapper.jar b/crmeb/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..2cc7d4a
Binary files /dev/null and b/crmeb/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/crmeb/.mvn/wrapper/maven-wrapper.properties b/crmeb/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..642d572
--- /dev/null
+++ b/crmeb/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
diff --git a/crmeb/README.md b/crmeb/README.md
new file mode 100644
index 0000000..485137e
--- /dev/null
+++ b/crmeb/README.md
@@ -0,0 +1,52 @@
+# 环境
+1. Java Jdk1.8
+2. Redis 5+
+3. Mysql 5.7+
+
+# Java项目框架
+1. SpringBoot 2.2.6.RELEASE
+2. Maven 3.6.1
+3. Swagger 2.9.2
+4. Mybatis Plus 3.3.1
+
+# 部署
+1. 拿到jar包,上传到web目录下,(宝塔配置的域名指向的web目录下即可)
+2. 在 jar包同级目录下运行 `start.sh (运行命令为 ./start.sh )` 脚本即可启动项目
+3. shell脚本会自动运行 `tail -f crmeb_out.file` 命令输出当前启动日志
+4. 看到 `Completed 200 OK` 表示启动成功
+5. 默认启动 `20000` 端口号
+
+
+#
+# 注意事项
+1. web端口号不可以设置为`20000`
+2. 反向代理地址: `http://127.0.0.1:20000` 【外网域名指向这个地址】
+
+# 二次开发帮助文档
+##注解参考:
+1. `@NotNull` 注解 作用类型 解释 任何类型 属性不能为 `null`
+2. `@NotEmpty` 集合 集合不能为 `null`,且 `size` 大于 `0`
+3. `@NotBlank` 只能作用在 `String` 上,不能为 `null`,而且调用 `trim()` 后,长度必须大于 `0`
+4. `@AssertTrue` `Boolean、boolean` 布尔属性必须是 `true`
+5. `@Min` 数字类型(原子和包装) 限定数字的最小值(整型)
+6. `@Max` 同 `@Min` 限定数字的最大值(整型)
+7. `@DecimalMin` 同 `@Min` 限定数字的最小值(字符串,可以是小数)
+8. `@DecimalMax` 同 `@Min` 限定数字的最大值(字符串,可以是小数)
+9. `@Range` 数字类型(原子和包装) 限定数字范围(长整型)
+10. `@Length` 字符串 限定字符串长度
+11. `@Size` 集合 限定集合大小
+12. `@Past` 时间、日期 必须是一个过去的时间或日期
+13. `@Future` 时期、时间 必须是一个未来的时间或日期
+14. `@Email` 字符串 必须是一个邮箱格式
+15. `@Pattern` 字符串、字符 正则匹配字符串
+
+# 产品复制
+1. 设置 [99api](https://www.99api.com "99api") 对应的api到配置表eb_system_config
+2. 配置baseUrl和key 实际的key可以根据自己的定义修改
+3. 目前支持天猫,京东,淘宝,苏宁,拼多多
+
+# 打印机
+1. [易联云文档](http://doc2.10ss.net/337744 "易联云文档")
+2. [易联云JAVA SDK](http://doc2.10ss.net/337744 "易联云JAVA SDK gitee文档")
+3. [如何导入第三方JAVA SDK包](https://blog.csdn.net/weixin_46028577/article/details/106342938?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase "如何导入第三方JAVA SDK包")
+
diff --git a/crmeb/crmeb-admin/pom.xml b/crmeb/crmeb-admin/pom.xml
new file mode 100644
index 0000000..c7d7994
--- /dev/null
+++ b/crmeb/crmeb-admin/pom.xml
@@ -0,0 +1,77 @@
+
+
+
+ crmeb
+ com.zbkj
+ 0.0.1-SNAPSHOT
+
+ 4.0.0
+
+ crmeb-admin
+ jar
+
+
+ 0.0.1-SNAPSHOT
+
+
+
+
+ com.zbkj
+ crmeb-service
+ ${crmeb-service}
+
+
+
+
+
+ Crmeb-admin
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 2.3.0.RELEASE
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
+
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/CrmebAdminApplication.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/CrmebAdminApplication.java
new file mode 100644
index 0000000..7951499
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/CrmebAdminApplication.java
@@ -0,0 +1,38 @@
+package com.zbkj.admin;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * 程序主入口
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@EnableAsync //开启异步调用
+@EnableSwagger2
+@Configuration
+@EnableTransactionManagement
+@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) //去掉数据源
+@ComponentScan(basePackages = {"com.zbkj"})
+@MapperScan(basePackages = {"com.zbkj.**.dao"})
+public class CrmebAdminApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(CrmebAdminApplication.class, args);
+ }
+
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/acpect/ControllerAspect.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/acpect/ControllerAspect.java
new file mode 100644
index 0000000..1e043a8
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/acpect/ControllerAspect.java
@@ -0,0 +1,53 @@
+package com.zbkj.admin.acpect;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+
+
+/**
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ * 所有的前端controller层的拦截业务,方法的执行时间长度,
+ */
+@Aspect
+@Component
+public class ControllerAspect {
+
+ Logger logger = LoggerFactory.getLogger(ControllerAspect.class);
+
+ @Pointcut("execution(* com.zbkj.admin.controller.*.*(..))")
+ private void pointCutMethodController() {
+
+ }
+
+ @Around("pointCutMethodController()")
+ public Object doAroundService(ProceedingJoinPoint pjp) throws Throwable {
+
+ long begin = System.nanoTime();
+
+ Object obj = pjp.proceed();
+
+ long end = System.nanoTime();
+
+ logger.info("Controller method:{},prams:{},cost time:{} ns,cost:{} ms",
+
+ pjp.getSignature().toString(), Arrays.toString(pjp.getArgs()), (end - begin), (end - begin) / 1000000);
+
+ return obj;
+ }
+
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/CorsConfig.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/CorsConfig.java
new file mode 100644
index 0000000..b28c73c
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/CorsConfig.java
@@ -0,0 +1,40 @@
+package com.zbkj.admin.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+/** 跨域配置
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Configuration
+public class CorsConfig{
+ private CorsConfiguration buildConfig() {
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ //允许任何域名
+ corsConfiguration.addAllowedOrigin("*");
+ //允许任何头
+ corsConfiguration.addAllowedHeader("*");
+ //允许任何方法
+ corsConfiguration.addAllowedMethod("*");
+ return corsConfiguration;
+ }
+
+ @Bean
+ public CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ //注册
+ source.registerCorsConfiguration("/**", buildConfig());
+ return new CorsFilter(source);
+ }
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/DruidConfig.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/DruidConfig.java
new file mode 100644
index 0000000..07d6b57
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/DruidConfig.java
@@ -0,0 +1,56 @@
+package com.zbkj.admin.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.druid.support.http.StatViewServlet;
+import com.alibaba.druid.support.http.WebStatFilter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+/**
+ * Druid配置组件
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Configuration
+public class DruidConfig {
+
+ @Bean
+ public ServletRegistrationBean druidServlet() { // 主要实现WEB监控的配置处理
+ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); // 进行druid监控的配置处理操作
+// servletRegistrationBean.addInitParameter("allow",
+// "127.0.0.1,192.168.1.159"); // 白名单
+// servletRegistrationBean.addInitParameter("deny", "192.168.1.200"); // 黑名单
+ servletRegistrationBean.addInitParameter("loginUsername", "kf"); // 用户名
+ servletRegistrationBean.addInitParameter("loginPassword", "654321"); // 密码
+ servletRegistrationBean.addInitParameter("resetEnable", "true"); // 是否可以重置数据源
+ return servletRegistrationBean ;
+ }
+ @Bean
+ public FilterRegistrationBean filterRegistrationBean() {
+ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean() ;
+ filterRegistrationBean.setFilter(new WebStatFilter());
+
+ filterRegistrationBean.addUrlPatterns("/*"); // 所有请求进行监控处理
+ //不必监控的请求
+ filterRegistrationBean.addInitParameter("exclusions", "*.html,*.png,*.ico,*.js,*.gif,*.jpg,*.css,/druid/*");
+ return filterRegistrationBean ;
+ }
+ @Bean("dataSource")
+ @ConfigurationProperties(prefix = "spring.datasource")
+ public DataSource druidDataSource() {
+ return new DruidDataSource();
+ }
+}
+
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/JacksonConfig.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/JacksonConfig.java
new file mode 100644
index 0000000..b67e03a
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/JacksonConfig.java
@@ -0,0 +1,36 @@
+package com.zbkj.admin.config;
+
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.math.BigDecimal;
+
+/**
+ * Jackjson配置组件
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Configuration
+public class JacksonConfig {
+
+ /**
+ * Jackson全局转化BigDecimal类型为String,解决jackson序列化时BigDecimal类型缺失精度问题
+ *
+ * @return Jackson2ObjectMapperBuilderCustomizer 注入的对象
+ */
+ @Bean
+ public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
+
+ return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.serializerByType(BigDecimal.class, ToStringSerializer.instance);
+ }
+
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/RestTemplateConfig.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/RestTemplateConfig.java
new file mode 100644
index 0000000..e06a3fc
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/RestTemplateConfig.java
@@ -0,0 +1,55 @@
+package com.zbkj.admin.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * RestTemplate配置组件
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Configuration
+public class RestTemplateConfig {
+ @Bean
+ public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
+ RestTemplate restTemplate = new RestTemplate(factory);
+ restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
+ restTemplate.getMessageConverters().add(new WxMappingJackson2HttpMessageConverter());
+ return restTemplate;
+ }
+
+ @Bean
+ public ClientHttpRequestFactory httpRequestFactory() {
+ SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
+ factory.setReadTimeout(10000);//ms
+ factory.setConnectTimeout(15000);//ms
+ return factory;
+ }
+
+ //解决微信返回json Content-Type 值却是 text/plain 的问题
+ public class WxMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
+ public WxMappingJackson2HttpMessageConverter(){
+ List mediaTypes = new ArrayList<>();
+ mediaTypes.add(MediaType.TEXT_PLAIN);
+ mediaTypes.add(MediaType.TEXT_HTML);
+ setSupportedMediaTypes(mediaTypes);
+ }
+ }
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/SchedulerConfig.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/SchedulerConfig.java
new file mode 100644
index 0000000..eacb337
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/SchedulerConfig.java
@@ -0,0 +1,36 @@
+package com.zbkj.admin.config;
+
+import lombok.Data;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.SchedulingConfigurer;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.scheduling.config.ScheduledTaskRegistrar;
+
+/**
+ * Spring 定时任务配置
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Data
+@Configuration
+public class SchedulerConfig implements SchedulingConfigurer {
+ private final int poolSize = 30;
+
+ @Override
+ public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
+ ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
+
+ threadPoolTaskScheduler.setPoolSize(getPoolSize());
+ threadPoolTaskScheduler.setThreadNamePrefix("crmeb-scheduled-task-pool-");
+ threadPoolTaskScheduler.initialize();
+
+ scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
+ }
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/SwaggerConfig.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/SwaggerConfig.java
new file mode 100644
index 0000000..9220217
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/SwaggerConfig.java
@@ -0,0 +1,129 @@
+package com.zbkj.admin.config;
+
+import com.zbkj.common.constants.Constants;
+import com.google.common.base.Predicate;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * Swagger配置组件
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Configuration
+@EnableSwagger2
+@ConfigurationProperties(prefix = "api.doc")
+public class SwaggerConfig{
+
+ //是否开启swagger,正式环境一般是需要关闭的,可根据springboot的多环境配置进行设置
+ Boolean swaggerEnabled = true;
+
+ @Value("${server.port}")
+ private String port;
+
+ @Value("${crmeb.domain}")
+ private String domain;
+
+ @Bean("admin")
+ public Docket createRestApis() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .groupName("admin")
+ .host(domain)
+ .apiInfo(apiInfo())
+ // 是否开启
+ .enable(swaggerEnabled)
+ .select()
+ // 扫描的路径包
+ .apis(RequestHandlerSelectors.basePackage("com.zbkj.admin"))
+ // 指定路径处理PathSelectors.any()代表所有的路径
+ .paths(adminPathsAnt())
+ .build()
+ .securitySchemes(security())
+ .securityContexts(securityContexts())
+// .globalOperationParameters(pars) // 针对单个url的验证 如果需要的话
+ .pathMapping("/");
+ }
+
+ @Bean("public")
+ public Docket create2RestApis() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .groupName("public")
+ .host(domain)
+ .apiInfo(apiInfo())
+ // 是否开启
+ .enable(swaggerEnabled)
+ .select()
+ // 扫描的路径包
+ .apis(RequestHandlerSelectors.basePackage("com.zbkj.admin"))
+ // 指定路径处理PathSelectors.any()代表所有的路径
+ .paths(publicPathsAnt()) //只监听
+ .build()
+ .securitySchemes(security())
+ .securityContexts(securityContexts())
+// .globalOperationParameters(pars) // 针对单个url的验证 如果需要的话
+ .pathMapping("/");
+ }
+
+ private Predicate adminPathsAnt() {
+ return PathSelectors.ant("/api/admin/**");
+ }
+
+ private Predicate publicPathsAnt() {
+ return PathSelectors.ant("/api/public/**");
+ }
+
+ private List security() {
+ return newArrayList(
+ new ApiKey(Constants.HEADER_AUTHORIZATION_KEY, Constants.HEADER_AUTHORIZATION_KEY, "header")
+ );
+ }
+
+ private ApiInfo apiInfo() {
+ return new ApiInfoBuilder()
+ .title("Crmeb Java")
+ .description("Crmeb")
+ .termsOfServiceUrl("http://host:port")
+ .version("1.0.0").build();
+ }
+
+
+ private List securityContexts() {
+ List res = new ArrayList<>();
+ res.add(SecurityContext.builder()
+ .securityReferences(defaultAuth())
+ .forPaths(PathSelectors.regex("/.*"))
+ .build());
+ return res;
+ }
+
+ private List defaultAuth() {
+ List res = new ArrayList<>();
+ AuthorizationScope authorizationScope = new AuthorizationScope("global", Constants.HEADER_AUTHORIZATION_KEY);
+ AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+ authorizationScopes[0] = authorizationScope;
+ res.add(new SecurityReference(Constants.HEADER_AUTHORIZATION_KEY, authorizationScopes));
+ return res;
+ }
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/TaskExecutorConfig.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/TaskExecutorConfig.java
new file mode 100644
index 0000000..5d1b876
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/TaskExecutorConfig.java
@@ -0,0 +1,105 @@
+package com.zbkj.admin.config;
+
+import lombok.Data;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * Task类的线程配置
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Data
+@Configuration
+public class TaskExecutorConfig {
+
+ //普通模式
+ private final int taskCorePoolSize = 20; //核心线程池数量
+ private final int taskMaxPoolSize = 100; //最大线程
+ private final int taskQueueCapacity = 200; //缓存队列条数
+ private final int taskKeepAliveSecond = 10; //允许的空闲时间
+ private final String taskNamePrefix = "task-executor-"; //线程名称前缀
+
+ //发布订阅模式
+// private final int listenerCorePoolSize = 3;
+// private final int listenerMaxPoolSize = 20;
+// private final int listenerQueueCapacity = 200;
+// private final int listenerKeepAliveSecond = 10;
+// private final String listenerNamePrefix = "listener-executor-";
+
+ //普通模式
+ @Bean("taskExecutor")
+ public ThreadPoolTaskExecutor taskExecutor(){
+ return initTaskExecutor(
+ getTaskCorePoolSize(),
+ getTaskMaxPoolSize(),
+ getTaskQueueCapacity(),
+ getTaskKeepAliveSecond(),
+ getTaskNamePrefix()
+ );
+ }
+
+// //针对发布订阅(pub listener) 的线程池
+// @Bean("listenerTaskExecutor")
+// public ThreadPoolTaskExecutor listenerTaskExecutor(){
+// return initTaskExecutor(getListenerCorePoolSize(), getListenerMaxPoolSize(),
+// getListenerQueueCapacity(), getListenerKeepAliveSecond(), getListenerNamePrefix());
+// }
+
+ /**
+ *
+ * 初始化TaskExecutor
+ * @param corePoolSize int 默认线程数
+ * @param maxPoolSize int 最大线程数
+ * @param queueCapacity int 缓冲队列长度
+ * @param keepAliveSecond int 允许空闲时间
+ * @param namePrefix String 名称的前缀
+ *
+ * @return ThreadPoolTaskExecutor
+ */
+ private ThreadPoolTaskExecutor initTaskExecutor(int corePoolSize, int maxPoolSize,
+ int queueCapacity, int keepAliveSecond, String namePrefix){
+ //callrunspolicy:由调度线程(提交任务的线程)处理该任务CallerRunsPolicy
+ return initTaskExecutor(corePoolSize, maxPoolSize, queueCapacity, keepAliveSecond, namePrefix,
+ new ThreadPoolExecutor.CallerRunsPolicy());
+ }
+
+ /**
+ * 初始化TaskExecutor
+ * @param corePoolSize int 默认线程数
+ * @param maxPoolSize int 最大线程数
+ * @param queueCapacity int 缓冲队列长度
+ * @param keepAliveSecond int 允许空闲时间
+ * @param namePrefix String 名称的前缀
+ * @param rejectedExecutionHandler 线程池满的时候如何处理
+ * @return ThreadPoolTaskExecutor
+ */
+ private ThreadPoolTaskExecutor initTaskExecutor(int corePoolSize, int maxPoolSize,
+ int queueCapacity, int keepAliveSecond, String namePrefix,
+ RejectedExecutionHandler rejectedExecutionHandler){
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(corePoolSize);//核心线程数(默认线程数)
+ executor.setMaxPoolSize(maxPoolSize);//最大线程数
+ executor.setQueueCapacity(queueCapacity);//缓冲队列数
+ executor.setKeepAliveSeconds(keepAliveSecond);//允许线程空闲时间(单位默认为秒)
+ executor.setThreadNamePrefix(namePrefix);//线程名前缀
+
+ //线程池对拒绝任务的处理策略,
+ executor.setRejectedExecutionHandler(rejectedExecutionHandler);
+
+ //初始化
+ executor.initialize();
+ return executor;
+ }
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/WebConfig.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/WebConfig.java
new file mode 100644
index 0000000..a71594d
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/WebConfig.java
@@ -0,0 +1,113 @@
+package com.zbkj.admin.config;
+
+import com.zbkj.admin.filter.ResponseFilter;
+import com.zbkj.common.config.CrmebConfig;
+import com.zbkj.common.constants.Constants;
+import com.zbkj.common.interceptor.SwaggerInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import org.springframework.web.servlet.handler.MappedInterceptor;
+
+/**
+ * token验证拦截器
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+ // 这里使用一个Bean为的是可以在拦截器中自由注入,也可以在拦截器中使用SpringUtil.getBean 获取
+ // 但是觉得这样更优雅
+
+ @Autowired
+ CrmebConfig crmebConfig;
+
+ @Bean
+ public ResponseFilter responseFilter(){ return new ResponseFilter(); }
+
+ @Value("${swagger.basic.username}")
+ private String username;
+ @Value("${swagger.basic.password}")
+ private String password;
+ @Value("${swagger.basic.check}")
+ private Boolean check;
+
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ //添加token拦截器
+ //addPathPatterns添加需要拦截的命名空间;
+ //excludePathPatterns添加排除拦截命名空间
+
+
+// //后台token拦截
+// registry.addInterceptor(adminTokenInterceptor()).
+// addPathPatterns("/api/admin/**").
+// excludePathPatterns("/api/admin/validate/**").
+// excludePathPatterns("/api/admin/login").
+// excludePathPatterns("/api/admin/logout").
+// excludePathPatterns("/api/admin/getLoginPic").
+// excludePathPatterns("/api/admin/wechat/config").
+// excludePathPatterns("/api/admin/authorize/login").
+// excludePathPatterns("/api/admin/payment/callback/**").
+//// excludePathPatterns("/api/admin/system/role/menu").
+// excludePathPatterns("/api/admin/system/role/info").
+// excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
+//
+// //后台权限规则
+// registry.addInterceptor(adminAuthInterceptor()).
+// addPathPatterns("/api/admin/**").
+// excludePathPatterns("/api/admin/validate/**").
+// excludePathPatterns("/api/admin/login").
+// excludePathPatterns("/api/admin/logout").
+// excludePathPatterns("/api/admin/getLoginPic").
+// excludePathPatterns("/api/admin/payment/callback/**").
+// excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
+
+ }
+
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ registry.addResourceHandler("/**")
+ .addResourceLocations("classpath:/static/");
+ registry.addResourceHandler("doc.html")
+ .addResourceLocations("classpath:/META-INF/resources/");
+ registry.addResourceHandler("/webjars/**")
+ .addResourceLocations("classpath:/META-INF/resources/webjars/");
+
+ /** 本地文件上传路径 */
+ registry.addResourceHandler(Constants.UPLOAD_TYPE_IMAGE + "/**")
+ .addResourceLocations("file:" + crmebConfig.getImagePath() + "/" + Constants.UPLOAD_TYPE_IMAGE + "/");
+ }
+
+ @Bean
+ public FilterRegistrationBean filterRegister() {
+ //注册过滤器
+ FilterRegistrationBean registration = new FilterRegistrationBean(responseFilter());
+ // 仅仅api前缀的请求才会拦截
+ registration.addUrlPatterns("/api/admin/*");
+ registration.addUrlPatterns("/api/front/*");
+ return registration;
+ }
+
+ /* 必须在此处配置拦截器,要不然拦不到swagger的静态资源 */
+ @Bean
+ @ConditionalOnProperty(name = "swagger.basic.enable", havingValue = "true")
+ public MappedInterceptor getMappedInterceptor() {
+ return new MappedInterceptor(new String[]{"/doc.html", "/webjars/**"}, new SwaggerInterceptor(username, password, check));
+ }
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/WebSecurityConfig.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/WebSecurityConfig.java
new file mode 100644
index 0000000..73912e8
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/config/WebSecurityConfig.java
@@ -0,0 +1,157 @@
+package com.zbkj.admin.config;
+
+import com.zbkj.admin.filter.JwtAuthenticationTokenFilter;
+import com.zbkj.admin.manager.AuthenticationEntryPointImpl;
+import com.zbkj.admin.manager.CustomAccessDeniedHandler;
+import com.zbkj.admin.manager.CustomAuthenticationProvider;
+import com.zbkj.common.constants.Constants;
+import com.zbkj.service.service.impl.UserDetailServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.authentication.logout.LogoutFilter;
+import org.springframework.web.filter.CorsFilter;
+
+/**
+ * Security配置
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ /**
+ * 跨域过滤器
+ */
+ @Autowired
+ private CorsFilter corsFilter;
+
+ /**
+ * token认证过滤器
+ */
+ @Bean
+ public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
+ return new JwtAuthenticationTokenFilter();
+ }
+
+ /**
+ * 认证失败处理类
+ */
+ @Bean
+ public AuthenticationEntryPointImpl unauthorizedHandler() {
+ return new AuthenticationEntryPointImpl();
+ }
+
+ /**
+ * 鉴权失败处理类
+ */
+ @Bean
+ public CustomAccessDeniedHandler accessDeniedHandler() {
+ return new CustomAccessDeniedHandler();
+ }
+
+ /**
+ * 这里将Spring Security自带的authenticationManager声明成Bean,声明它的作用是用它帮我们进行认证操作,
+ * 调用这个Bean的authenticate方法会由Spring Security自动帮我们做认证。
+ */
+// @Bean
+// public AuthenticationManager authenticationManager() throws Exception {
+// return new CusAuthenticationManager(customAuthenticationProvider);
+// }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) {
+ auth.authenticationProvider(new CustomAuthenticationProvider(new UserDetailServiceImpl()));
+ }
+
+ /**
+ * anyRequest | 匹配所有请求路径
+ * access | SpringEl表达式结果为true时可以访问
+ * anonymous | 匿名可以访问
+ * denyAll | 用户不能访问
+ * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
+ * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
+ * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
+ * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
+ * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
+ * hasRole | 如果有参数,参数表示角色,则其角色可以访问
+ * permitAll | 用户可以任意访问
+ * rememberMe | 允许通过remember-me登录的用户访问
+ * authenticated | 用户登录后可访问
+ */
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+
+ // CRSF禁用,因为不使用session
+ http.cors().and().csrf().disable()
+ // 认证失败处理类
+ .exceptionHandling().authenticationEntryPoint(unauthorizedHandler())
+ .accessDeniedHandler(accessDeniedHandler()).and()
+ // 基于token,所以不需要session
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
+ // 过滤请求
+ .authorizeRequests()
+ // 跨域预检请求
+// .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
+ // 对于登录login 验证码captchaImage 和其他放行的目录 允许匿名访问"/citylife/front/**"
+ .antMatchers("/api/admin/login", "/api/admin/validate/code/get").permitAll()
+ .antMatchers("/api/admin/getLoginPic").permitAll()
+ // 放行资源路径
+ .antMatchers("/"+ Constants.UPLOAD_TYPE_IMAGE +"/**").anonymous()
+ // 放行图片、文件上传
+ .antMatchers("/api/admin/upload/image").permitAll()
+ .antMatchers("/api/admin/upload/file").permitAll()
+ // 代码生成器
+ .antMatchers("/api/codegen/code").permitAll()
+// .antMatchers("/wx/user/*/login","/citylife/nocheck/**").anonymous()
+ .antMatchers(
+ HttpMethod.GET,
+ "/*.html",
+ "/**/*.html",
+ "/**/*.css",
+ "/**/*.js"
+ ).permitAll()
+ .antMatchers("/profile/**").anonymous()
+ .antMatchers("/common/download**").anonymous()
+ .antMatchers("/common/download/resource**").anonymous()
+ .antMatchers("/doc.html").permitAll()
+ .antMatchers("/swagger-resources/**").permitAll()
+ .antMatchers("/webjars/**").permitAll()
+ .antMatchers("/v2/**").permitAll()
+ .antMatchers("/swagger-ui.html/**").permitAll()
+ .antMatchers("/*/api-docs").anonymous()
+ .antMatchers("/druid/**").anonymous()
+ .antMatchers("/captcha/get", "/captcha/check").anonymous()
+ .antMatchers("/api/admin/payment/callback/**").anonymous()
+ .antMatchers("/api/public/**").anonymous()
+ // 除上面外的所有请求全部需要鉴权认证
+ .anyRequest().authenticated()
+ .and()
+ .headers().frameOptions().disable();// 防止iframe 造成跨域
+// http.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
+ // 添加JWT filter
+ // 开启登录认证流程过滤器
+ http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
+ // 添加CORS filter
+ http.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
+ http.addFilterBefore(corsFilter, LogoutFilter.class);
+ }
+
+}
diff --git a/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/controller/AdminLoginController.java b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/controller/AdminLoginController.java
new file mode 100644
index 0000000..110bc28
--- /dev/null
+++ b/crmeb/crmeb-admin/src/main/java/com/zbkj/admin/controller/AdminLoginController.java
@@ -0,0 +1,86 @@
+package com.zbkj.admin.controller;
+
+import com.zbkj.common.request.SystemAdminLoginRequest;
+import com.zbkj.common.response.CommonResult;
+import com.zbkj.common.response.MenusResponse;
+import com.zbkj.common.response.SystemAdminResponse;
+import com.zbkj.common.response.SystemLoginResponse;
+import com.zbkj.common.utils.CrmebUtil;
+import com.zbkj.admin.service.AdminLoginService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 管理端登录服务
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team
+ * +----------------------------------------------------------------------
+ */
+@Slf4j
+@RestController
+@RequestMapping("api/admin")
+@Api(tags = "管理端登录服务")
+public class AdminLoginController {
+
+ @Autowired
+ private AdminLoginService adminLoginService;
+
+ @ApiOperation(value="PC登录")
+ @PostMapping(value = "/login", produces = "application/json")
+ public CommonResult SystemAdminLogin(@RequestBody @Validated SystemAdminLoginRequest systemAdminLoginRequest, HttpServletRequest request) {
+ String ip = CrmebUtil.getClientIp(request);
+ SystemLoginResponse systemAdminResponse = adminLoginService.login(systemAdminLoginRequest, ip);
+ return CommonResult.success(systemAdminResponse, "login success");
+ }
+
+ @PreAuthorize("hasAuthority('admin:logout')")
+ @ApiOperation(value="PC登出")
+ @GetMapping(value = "/logout")
+ public CommonResult SystemAdminLogout() {
+ adminLoginService.logout();
+ return CommonResult.success("logout success");
+ }
+
+ @PreAuthorize("hasAuthority('admin:info')")
+ @ApiOperation(value="获取用户详情")
+ @GetMapping(value = "/getAdminInfoByToken")
+ public CommonResult getAdminInfo() {
+ return CommonResult.success(adminLoginService.getInfoByToken());
+ }
+
+ /**
+ * 获取登录页图片
+ * @return Map
+ */
+ @ApiOperation(value = "获取登录页图片")
+ @RequestMapping(value = "/getLoginPic", method = RequestMethod.GET)
+ public CommonResult