(WxMall.class);
+ // value值的序列化
+ template.setValueSerializer(j);
+ template.setHashKeySerializer(j);
+
+ // key的序列化
+ template.setKeySerializer(new StringRedisSerializer());
+ template.setHashKeySerializer(new StringRedisSerializer());
+
+ template.setConnectionFactory(connectionFactory);
+ return template;
+ }
+
+}
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/config/RestFilter.java b/mallinkSysAdmin/src/main/java/com/iformall/config/RestFilter.java
new file mode 100644
index 000000000..4f9298433
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/config/RestFilter.java
@@ -0,0 +1,58 @@
+package com.iformall.config;
+
+import java.io.IOException;
+import java.util.Optional;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 前后端分离RESTful接口过滤器
+ *
+ * @author xuguoqin
+ *
+ */
+public class RestFilter implements Filter {
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ HttpServletRequest req = null;
+ if (request instanceof HttpServletRequest) {
+ req = (HttpServletRequest) request;
+ }
+ HttpServletResponse res = null;
+ if (response instanceof HttpServletResponse) {
+ res = (HttpServletResponse) response;
+ }
+ if (req != null && res != null) {
+ //设置允许传递的参数
+ res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
+ //设置允许带上cookie
+ res.setHeader("Access-Control-Allow-Credentials", "true");
+ String origin = Optional.ofNullable(req.getHeader("Origin")).orElse(req.getHeader("Referer"));
+ //设置允许的请求来源
+ res.setHeader("Access-Control-Allow-Origin", origin);
+ //设置允许的请求方法
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS");
+ }
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/config/RestTemplateConfig.java b/mallinkSysAdmin/src/main/java/com/iformall/config/RestTemplateConfig.java
new file mode 100644
index 000000000..560a77cb5
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/config/RestTemplateConfig.java
@@ -0,0 +1,24 @@
+package com.iformall.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+public class RestTemplateConfig {
+
+ @Bean
+ public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
+ return new RestTemplate(factory);
+ }
+
+ @Bean
+ public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
+ SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
+ factory.setReadTimeout(5000);//ms
+ factory.setConnectTimeout(10000);//ms
+ return factory;
+ }
+}
\ No newline at end of file
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/config/ShiroConfig.java b/mallinkSysAdmin/src/main/java/com/iformall/config/ShiroConfig.java
new file mode 100644
index 000000000..112d749b2
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/config/ShiroConfig.java
@@ -0,0 +1,317 @@
+package com.iformall.config;
+
+import com.iformall.service.MallPermissionService;
+import com.iformall.shiro.MyRetryLimitCredentialsMatcher;
+import com.iformall.shiro.MyShiroRealm;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.spring.LifecycleBeanPostProcessor;
+import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.apache.shiro.web.servlet.SimpleCookie;
+import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+import org.crazycake.shiro.RedisCacheManager;
+import org.crazycake.shiro.RedisManager;
+import org.crazycake.shiro.RedisSessionDAO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.servlet.Filter;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+
+/**
+ * Created by yangqj on 2017/4/23.
+ */
+@Configuration
+public class ShiroConfig {
+
+ @Value("${spring.redis.host}")
+ private String host;
+
+ @Value("${spring.redis.port}")
+ private int port;
+
+ @Value("${spring.redis.timeout}")
+ private int timeout;
+
+ @Value("${spring.redis.expire}")
+ private int expire;
+
+ @Value("${spring.redis.password}")
+ private String password;
+
+ @Bean
+ public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
+ return new LifecycleBeanPostProcessor();
+ }
+
+ /**
+ * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean
+ * @return
+ */
+// @Bean
+// public ShiroDialect shiroDialect() {
+// return new ShiroDialect();
+// }
+
+ /**
+ * ShiroFilterFactoryBean 处理拦截资源文件问题。
+ * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,因为在
+ * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
+ *
+ * Filter Chain定义说明
+ * 1、一个URL可以配置多个Filter,使用逗号分隔
+ * 2、当设置多个过滤器时,全部验证通过,才视为通过
+ * 3、部分过滤器可指定参数,如perms,roles
+ */
+ @Bean
+ public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
+ System.out.println("ShiroConfiguration.shirFilter()");
+ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
+ // 必须设置 SecurityManager
+ shiroFilterFactoryBean.setSecurityManager(securityManager);
+ Map filters = new LinkedHashMap();
+ filters.put("token", new ShiroLoginFilter());
+ filters.put("corsFilter", new RestFilter());
+ //filters.put("authc", new MyFormAuthenticationFilter());
+ shiroFilterFactoryBean.setFilters(filters);
+ // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
+ shiroFilterFactoryBean.setLoginUrl("/#/");
+ // 登录成功后要跳转的链接
+
+ shiroFilterFactoryBean.setSuccessUrl("/usersPage");
+ //未授权界面;
+ shiroFilterFactoryBean.setUnauthorizedUrl("/403");
+ //拦截器.
+ Map filterChainDefinitionMap = new LinkedHashMap();
+
+ //filterChainDefinitionMap.put("/ue/**", "anon");
+ //filterChainDefinitionMap.put("/config.json", "anon");
+ // login
+ filterChainDefinitionMap.put("/doLogin/**", "anon");
+ filterChainDefinitionMap.put("/bHidLogin/**", "anon");
+ filterChainDefinitionMap.put("/sendLoginPhoneCode/**", "anon");
+ filterChainDefinitionMap.put("/doLoginByPhone/**", "anon");
+ filterChainDefinitionMap.put("/wechat/login", "anon"); // 微信第三方登录callback
+ filterChainDefinitionMap.put("/wechat/callback", "anon"); // 微信网页登录回调
+ filterChainDefinitionMap.put("/wechat/weChatUserLogin", "anon"); // 微信第三方登录
+ // 验证码
+ filterChainDefinitionMap.put("/captcha.jpg", "anon");
+ // 官网
+ filterChainDefinitionMap.put("/wxMallApply/add", "anon");
+ // callback
+ filterChainDefinitionMap.put("/wxPay/notify/**", "anon"); // 支付回调
+ filterChainDefinitionMap.put("/wxPayBill/notify/**", "anon");
+ filterChainDefinitionMap.put("/wxMsgCallback/**", "anon");
+ filterChainDefinitionMap.put("/user/sendvalidationcode", "anon");
+ filterChainDefinitionMap.put("/user/updatepwd", "anon");
+ filterChainDefinitionMap.put("/carCallback/**", "anon");
+ filterChainDefinitionMap.put("/wxMallApply/sendvalidationcode", "anon");
+
+ // static files
+ filterChainDefinitionMap.put("/css/**", "anon");
+ filterChainDefinitionMap.put("/js/**", "anon");
+ filterChainDefinitionMap.put("/img/**", "anon");
+ filterChainDefinitionMap.put("/font-awesome/**", "anon");
+
+ //:这是一个坑呢,一不小心代码就不好使了;
+ //
+ //自定义加载权限资源关系
+// Map map = new HashMap<>();
+// List resourcesList = resourcesService.list(map);
+// for(SysPermission resources:resourcesList){
+//
+// if (StringUtil.isNotEmpty(resources.getUrl())) {
+// String permission = "perms[" + resources.getUrl()+ "]";
+// filterChainDefinitionMap.put(resources.getUrl(),permission);
+// }
+// }
+ // swagger-ui
+ filterChainDefinitionMap.put("/swagger-ui.html", "anon");
+ filterChainDefinitionMap.put("/v2/**", "anon");
+ filterChainDefinitionMap.put("/swagger-resources/**", "anon");
+ filterChainDefinitionMap.put("/webjars/**", "anon");
+
+ filterChainDefinitionMap.put("/version", "anon");
+ filterChainDefinitionMap.put("/wxDeviceScreenAd/**", "anon");
+// filterChainDefinitionMap.put("/role/**", "corsFilter,token");
+
+
+ //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
+ filterChainDefinitionMap.put("/logout", "authc");
+
+ filterChainDefinitionMap.put("/**", "corsFilter,token,authc");
+// filterChainDefinitionMap.put("/**", "anon");
+
+
+ shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
+ return shiroFilterFactoryBean;
+ }
+
+
+ public static boolean isAjax(ServletRequest request) {
+ String header = ((HttpServletRequest) request).getHeader("X-Requested-With");
+ if ("XMLHttpRequest".equalsIgnoreCase(header)) {
+ System.out.println("当前请求为Ajax请求");
+ return Boolean.TRUE;
+ }
+ System.out.println("当前请求非Ajax请求");
+ return Boolean.FALSE;
+ }
+
+ @Bean
+ public SecurityManager securityManager(@Qualifier("myRetryLimitCredentialsMatcher") MyRetryLimitCredentialsMatcher matcher) {
+ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+ //设置realm.
+ securityManager.setRealm(myShiroRealm(matcher));
+ // 自定义缓存实现 使用redis
+ //securityManager.setCacheManager(cacheManager());
+ // 自定义session管理 使用redis
+ securityManager.setSessionManager(sessionManager());
+ return securityManager;
+ }
+
+ @Bean
+ public MyShiroRealm myShiroRealm(MyRetryLimitCredentialsMatcher matcher) {
+ MyShiroRealm myShiroRealm = new MyShiroRealm();
+ myShiroRealm.setCredentialsMatcher(matcher);
+ return myShiroRealm;
+ }
+
+
+ /**
+ * 密码匹配凭证管理器 凭证匹配器
+ * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
+ * 所以我们需要修改下doGetAuthenticationInfo中的代码;
+ * )
+ *
+ * @return
+ */
+ @Bean(name = "myRetryLimitCredentialsMatcher")
+ public MyRetryLimitCredentialsMatcher hashedCredentialsMatcher() {
+ MyRetryLimitCredentialsMatcher hashedCredentialsMatcher = new MyRetryLimitCredentialsMatcher();
+
+ hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
+ hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
+
+ return hashedCredentialsMatcher;
+ }
+
+
+ /**
+ * 开启shiro aop注解支持.
+ * 使用代理方式;所以需要开启代码支持;
+ *
+ * @param securityManager
+ * @return
+ */
+ @Bean
+ public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
+ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
+ authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
+ return authorizationAttributeSourceAdvisor;
+ }
+
+ /**
+ * 配置shiro redisManager
+ * 使用的是shiro-redis开源插件
+ *
+ * @return
+ */
+ public RedisManager redisManager() {
+ RedisManager redisManager = new RedisManager();
+ redisManager.setHost(host);
+ redisManager.setPort(port);
+ //redisManager.setExpire(expire);// 配置缓存过期时间
+ redisManager.setTimeout(timeout);
+ redisManager.setPassword(password);
+ return redisManager;
+ }
+
+ /**
+ * cacheManager 缓存 redis实现
+ * 使用的是shiro-redis开源插件
+ *
+ * @return
+ */
+ public RedisCacheManager cacheManager() {
+ RedisCacheManager redisCacheManager = new RedisCacheManager();
+ redisCacheManager.setRedisManager(redisManager());
+ return redisCacheManager;
+ }
+
+
+ /**
+ * RedisSessionDAO shiro sessionDao层的实现 通过redis
+ * 使用的是shiro-redis开源插件
+ */
+ @Bean
+ public RedisSessionDAO redisSessionDAO() {
+ RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
+ redisSessionDAO.setRedisManager(redisManager());
+ return redisSessionDAO;
+ }
+
+ /**
+ * shiro session的管理
+ */
+ @Bean
+ public DefaultWebSessionManager sessionManager() {
+ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
+ //设置session过期时间为1小时(单位:毫秒),默认为30分钟
+ sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
+ sessionManager.setSessionValidationSchedulerEnabled(true);
+ sessionManager.setSessionIdUrlRewritingEnabled(false);
+
+ sessionManager.setSessionDAO(redisSessionDAO());
+ sessionManager.setSessionIdCookie(simpleCookie());
+ return sessionManager;
+ }
+
+ @Bean
+ public SimpleCookie simpleCookie() {
+ SimpleCookie simpleCookie = new SimpleCookie("SSIDS");
+ simpleCookie.setDomain("");
+ return simpleCookie;
+ }
+
+// @Bean
+// public SimpleCookie rememberMeCookie(){
+// //System.out.println("ShiroConfiguration.rememberMeCookie()");
+// //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
+// SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
+// //
+// simpleCookie.setMaxAge(60*30);
+// return simpleCookie;
+// }
+
+// @Bean
+// public CookieRememberMeManager rememberMeManager(){
+// //System.out.println("ShiroConfiguration.rememberMeManager()");
+// CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
+// cookieRememberMeManager.setCookie(rememberMeCookie());
+// //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
+// cookieRememberMeManager.setCipherKey(Base64.decodeBytes("2AvVhdsgUs0FSA3SDFAdag=="));
+// return cookieRememberMeManager;
+// }
+
+// @Bean(name = "securityManager")
+// public DefaultWebSecurityManager defaultWebSecurityManager(MyShiroRealm realm){
+// DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+// //设置realm
+// securityManager.setRealm(realm);
+// //用户授权/认证信息Cache, 采用EhCache缓存
+// securityManager.setCacheManager(cacheManager());
+// //注入记住我管理器
+// securityManager.setRememberMeManager(rememberMeManager());
+// return securityManager;
+// }
+
+}
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/config/ShiroLoginFilter.java b/mallinkSysAdmin/src/main/java/com/iformall/config/ShiroLoginFilter.java
new file mode 100644
index 000000000..67c07385e
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/config/ShiroLoginFilter.java
@@ -0,0 +1,31 @@
+package com.iformall.config;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
+
+import com.alibaba.fastjson.JSON;
+import com.iformall.common.ResultData;
+public class ShiroLoginFilter extends FormAuthenticationFilter {
+
+ @Override
+ protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+ response.setCharacterEncoding("UTF-8");
+ response.setContentType("application/json");
+ ResultData resultData = new ResultData(ResultData.UNLOGIN,"用户未登录");
+ response.getWriter().write(JSON.toJSONString(resultData));
+ return false;
+ }
+
+ /**
+ * 判断ajax请求
+ * @param request
+ * @return
+ */
+ boolean isAjax(HttpServletRequest request){
+ return (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals( request.getHeader("X-Requested-With").toString()) ) ;
+ }
+
+}
\ No newline at end of file
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/config/WebConfig.java b/mallinkSysAdmin/src/main/java/com/iformall/config/WebConfig.java
new file mode 100644
index 000000000..d08ea21f5
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/config/WebConfig.java
@@ -0,0 +1,151 @@
+package com.iformall.config;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationConfig;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.iformall.interceptor.HttpServletRequestWrapperFilter;
+import com.iformall.interceptor.RequestInterceptor;
+import com.iformall.ueditor.ActionEnter;
+import com.iformall.ueditor.ConfigManager;
+import com.iformall.ueditor.UEditorConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CharacterEncodingFilter;
+import org.springframework.web.filter.CorsFilter;
+import org.springframework.web.servlet.config.annotation.*;
+
+import javax.servlet.Filter;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+@Configuration
+@EnableWebMvc
+@EnableConfigurationProperties({UEditorConfig.class, AwsProperty.class})
+public class WebConfig implements WebMvcConfigurer {
+ @Autowired
+ private UEditorConfig uEditorConfig;
+
+ @Autowired
+ private AwsProperty awsProperty;
+
+ @Autowired
+ private RequestInterceptor requestInterceptor;
+
+ @Bean
+ @ConditionalOnMissingBean(ActionEnter.class)
+ public ActionEnter actionEnter() {
+ ActionEnter actionEnter = new ActionEnter(ConfigManager.getInstance(uEditorConfig, awsProperty));
+ return actionEnter;
+ }
+
+ @Bean
+ public CorsFilter corsFilter() {
+ final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
+ final CorsConfiguration corsConfiguration = new CorsConfiguration();
+ // 允许cookies跨域
+ corsConfiguration.setAllowCredentials(true);
+ // 允许向该服务器提交请求的URI, *表示全部允许
+ corsConfiguration.addAllowedOrigin("*");
+ // 允许访问的头信息,*表示全部
+ corsConfiguration.addAllowedHeader("*");
+ // 允许提交请求的方法, *表示全部允许
+ corsConfiguration.addAllowedMethod("*");
+ urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
+ return new CorsFilter(urlBasedCorsConfigurationSource);
+ }
+
+ /**
+ * 用于处理编码问题
+ *
+ * @return
+ */
+ @Bean
+ public Filter characterEncodingFilter() {
+ CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
+ characterEncodingFilter.setEncoding("UTF-8");
+ characterEncodingFilter.setForceEncoding(true);
+ return characterEncodingFilter;
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(requestInterceptor).addPathPatterns("/**");
+ }
+
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ registry.addResourceHandler("swagger-ui.html")
+ .addResourceLocations("classpath:/META-INF/resources/");
+ registry.addResourceHandler("/webjars/**")
+ .addResourceLocations("classpath:/META-INF/resources/webjars/");
+ // ueditor
+ registry.addResourceHandler("/upload/**")
+ .addResourceLocations("file:" + uEditorConfig.getUploadPath());
+ registry.addResourceHandler("/config.json").addResourceLocations("classpath:/config.json");
+
+ }
+
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("*")
+ .allowCredentials(true)
+ .allowedMethods("GET", "POST", "DELETE", "PUT")
+ .maxAge(3600);
+ }
+
+ @Override
+ public void configureMessageConverters(List> converters) {
+ MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
+ //ObjectMapper 是Jackson库的主要类。它提供一些功能将转换成Java对象匹配JSON结构,反之亦然
+ ObjectMapper objectMapper = new ObjectMapper();
+ SimpleModule simpleModule = new SimpleModule();
+
+ //不显示为null的字段
+ objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+
+ DeserializationConfig dc = objectMapper.getDeserializationConfig();
+ // 设置反序列化日期格式、忽略不存在get、set的属性
+ objectMapper.setConfig(
+ dc.with(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
+ .without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
+ );
+
+ //序列化将Long转String类型
+ simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
+ simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
+ SimpleModule bigIntegerModule = new SimpleModule();
+ //序列化将BigInteger转String类型
+ bigIntegerModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
+ SimpleModule bigDecimalModule = new SimpleModule();
+ //序列化将BigDecimal转String类型
+ bigDecimalModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
+ objectMapper.registerModule(simpleModule);
+ objectMapper.registerModule(bigDecimalModule);
+ objectMapper.registerModule(bigIntegerModule);
+ jackson2HttpMessageConverter.setObjectMapper(objectMapper);
+ converters.add(jackson2HttpMessageConverter);
+ }
+
+ @Bean
+ public FilterRegistrationBean Filters() {
+ FilterRegistrationBean registrationBean = new FilterRegistrationBean();
+ registrationBean.setFilter(new HttpServletRequestWrapperFilter());
+ registrationBean.addUrlPatterns("/*");
+ registrationBean.setName("koalaSignFilter");
+ return registrationBean;
+ }
+}
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/config/WechatMpConfig.java b/mallinkSysAdmin/src/main/java/com/iformall/config/WechatMpConfig.java
new file mode 100644
index 000000000..4dff6c762
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/config/WechatMpConfig.java
@@ -0,0 +1,33 @@
+package com.iformall.config;
+
+import me.chanjar.weixin.mp.api.WxMpConfigStorage;
+import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+public class WechatMpConfig {
+
+ @Autowired
+ private WechatWebProperties wechatWebProperties;
+
+ @Bean
+ public WxMpService wxMpService() {
+ //创建WxMpService实例并设置appid和sectret
+ WxMpService wxMpService = new WxMpServiceImpl();
+ //这里的设置方式是跟着这个sdk的文档写的
+ wxMpService.setWxMpConfigStorage(wxConfigProvider());
+ return wxMpService;
+ }
+
+ @Bean
+ public WxMpConfigStorage wxConfigProvider(){
+ WxMpInMemoryConfigStorage wxConfigProvider = new WxMpInMemoryConfigStorage();
+ wxConfigProvider.setAppId(wechatWebProperties.getAppId());
+ wxConfigProvider.setSecret(wechatWebProperties.getSecret());
+ return wxConfigProvider;
+ }
+}
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/config/WechatWebProperties.java b/mallinkSysAdmin/src/main/java/com/iformall/config/WechatWebProperties.java
new file mode 100644
index 000000000..0b9047399
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/config/WechatWebProperties.java
@@ -0,0 +1,59 @@
+package com.iformall.config;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * Stormeye
+ */
+@Component
+@ConfigurationProperties(prefix = "wechat.web")
+public class WechatWebProperties {
+ /**
+ * 设置微信第三方平台-微信登录的web应用appid
+ */
+ private String appId;
+
+ /**
+ * 设置微信第三方平台-微信登录的web应用app secret
+ */
+ private String secret;
+
+ /**
+ * 网页URL
+ * @return
+ */
+ private String url;
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getSecret() {
+ return secret;
+ }
+
+ public void setSecret(String secret) {
+ this.secret = secret;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this,
+ ToStringStyle.MULTI_LINE_STYLE);
+ }
+}
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/controller/app/WxAppinfoController.java b/mallinkSysAdmin/src/main/java/com/iformall/controller/app/WxAppinfoController.java
new file mode 100644
index 000000000..133f7ea0e
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/controller/app/WxAppinfoController.java
@@ -0,0 +1,245 @@
+package com.iformall.controller.app;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor;
+import com.github.pagehelper.PageInfo;
+import com.iformall.common.ErrorCode;
+import com.iformall.common.Result;
+import com.iformall.common.ResultData;
+import com.iformall.controller.base.BaseController;
+import com.iformall.domain.po.WxAppinfo;
+import com.iformall.exception.MallinkException;
+import com.iformall.service.WxAppinfoService;
+import com.iformall.service.wechat.FmOpenService;
+import com.iformall.utils.Constant;
+import com.iformall.utils.MaUtil;
+import com.iformall.utils.QRCodeUtils;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+@RestController
+@RequestMapping("wxAppinfo")
+public class WxAppinfoController extends BaseController {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Autowired
+ private boolean isFmOpen;
+
+ @Autowired
+ private WxAppinfoService wxAppinfoService;
+
+ @Autowired
+ private FmOpenService openService;
+
+ @ApiOperation("分页列表接口")
+ @GetMapping("list")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true),
+ @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)})
+ public ResultData list(@ModelAttribute WxAppinfo wxAppinfo, Integer pageNum, Integer pageSize) {
+ logger.debug("[" + getIpAddr() + "] WxAppinfoController::list");
+ if (null == wxAppinfo) wxAppinfo = new WxAppinfo();
+ final PageInfo page = wxAppinfoService.listAsPage(wxAppinfo, pageNum, pageSize);
+ return new ResultData(page);
+ }
+
+ @ApiOperation("新增接口")
+ @PostMapping("add")
+ public ResultData add(@RequestBody WxAppinfo wxAppinfo) {
+ logger.debug("[" + getIpAddr() + "] WxAppinfoController::add");
+ //Assert.notNull(wxAppinfo.getName(), "角色名不能为空");
+ //Assert.isTrue(!checkUnique(sysRole.getName(), null), "重复的角色名");
+ wxAppinfoService.saveOrUpdate(wxAppinfo);
+ return new ResultData();
+ }
+
+ @ApiOperation("根据id更新接口")
+ @PostMapping("update")
+ public ResultData update(@RequestBody WxAppinfo wxAppinfo) {
+ logger.debug("[" + getIpAddr() + "] WxAppinfoController::update");
+ wxAppinfoService.saveOrUpdate(wxAppinfo);
+ return new ResultData();
+ }
+
+ @ApiOperation("根据id删除接口")
+ @GetMapping("/del")
+ @ApiImplicitParam(name = "id", value = "id", dataType = "Long", paramType = "query", required = true)
+ public ResultData delete(Long id) {
+ logger.debug("[" + getIpAddr() + "] WxAppinfoController::delete");
+ wxAppinfoService.deleteById(id);
+ return new ResultData(Result.SUCCESS, "删除成功", null);
+ }
+
+ @ApiOperation("根据id查询接口")
+ @GetMapping("/findById")
+ @ApiImplicitParam(name = "id", value = "id", dataType = "Long", paramType = "query", required = true)
+ public ResultData findById(Long id) {
+ logger.debug("[" + getIpAddr() + "] WxAppinfoController::findById");
+ return new ResultData(Result.SUCCESS, "查询成功", wxAppinfoService.getById(id));
+ }
+
+ @ApiOperation(value = "下载二维码", produces="application/json;charset=UTF-8", notes = "参数{\"name\":\"String\",\"pageUrl\":\"String\", \"sceneParam\":\"二维码参数\", \"type\":0:有限二维码,1:无限二维码,\"withText\":int(0:不带字, 1:加一行字,2:加两行字),\"text1\":\"String\",\"text2\":\"String\"}")
+ @PostMapping("/downQrCode")
+ public void downQrCode(HttpServletRequest request, HttpServletResponse response, @RequestBody Map params) throws MallinkException {
+ logger.debug("[" + getIpAddr() + "] WxAppinfoController::downQrCode");
+ String name = (String) params.get("name");
+ String pageUrl = (String) params.get("pageUrl");
+ String sceneParam = (String) params.get("sceneParam");
+ int type = 0;
+ try {
+ type = (int) params.get("type");
+ } catch (Exception e) {
+ type = 0;
+ }
+
+ int withText = 0;
+ try {
+ withText = (int) params.get("withText");
+ } catch (Exception e) {
+ withText = 0;
+ }
+ String text1 = (String) params.get("text1");
+ String text2 = (String) params.get("text2");
+ if (StringUtils.isBlank(pageUrl)) {
+ throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "pageUrl不能为空");
+ }
+ try {
+ exportQrcode(request, response,
+ getTenantId(), type, pageUrl, sceneParam,
+ withText, text1, text2,
+ name);
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ throw new MallinkException(Result.ERROR, "下载异常");
+ }
+ }
+
+ private void exportQrcode(HttpServletRequest request, HttpServletResponse response,
+ String tenantId, int type, String pageUrl, String sceneParam,
+ int withText, String text1, String text2,
+ String name) {
+ // type 0 有限二维码, 1 无限制二维码
+ // withText 0 不带字 1. 带下面的字,2 带下面的两行字
+ WxAppinfo appinfo = wxAppinfoService.getCAppInfo(tenantId);
+ boolean autoColor = false;
+ boolean isHyaline = true;
+ WxMaCodeLineColor color = new WxMaCodeLineColor("0", "0", "0");
+
+ WxMaService wxMaService;
+ if(isFmOpen) {
+ wxMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appinfo.getAppId());
+ } else {
+ wxMaService = MaUtil.getWeappService(appinfo);
+ }
+
+ String pathStr = "";
+ if (StringUtils.isNotBlank(sceneParam)) {
+ pathStr = pageUrl + "?scene="+sceneParam;
+ } else {
+ pathStr = pageUrl;
+ }
+
+
+ String filepath = Constant.fileDirectory;
+ String fileName = name + ".png";
+ String destPath1 = filepath + "1_" + fileName;
+ String destPath = filepath + fileName;
+
+ File dest = new File(destPath);
+ File pDest = dest.getParentFile();
+ if (!pDest.exists()) {
+ pDest.mkdirs();
+ }
+ try {
+ if(type == 0) {
+ final File codeFile = wxMaService.getQrcodeService().createQrcode(pathStr, QRCodeUtils.QR_WIDTH);
+ if (withText == 1) {
+ File dest1 = new File(destPath1);
+ org.apache.commons.io.FileUtils.copyFile(codeFile, dest1);
+ QRCodeUtils.graphicsGeneration(dest1, dest, text1);
+ org.apache.commons.io.FileUtils.forceDelete(dest1);
+ } else if (withText == 2) {
+ File dest1 = new File(destPath1);
+ org.apache.commons.io.FileUtils.copyFile(codeFile, dest1);
+ QRCodeUtils.graphicsGeneration2(dest1, dest, text1, text2);
+ org.apache.commons.io.FileUtils.forceDelete(dest1);
+ } else {
+ org.apache.commons.io.FileUtils.copyFile(codeFile, dest);
+ }
+ org.apache.commons.io.FileUtils.forceDelete(codeFile);
+ } else {
+ final File codeFile = wxMaService.getQrcodeService().createWxaCodeUnlimit(sceneParam, pageUrl, QRCodeUtils.QR_WIDTH, autoColor, color, isHyaline);
+ if (withText == 1) {
+ File dest1 = new File(destPath1);
+ org.apache.commons.io.FileUtils.copyFile(codeFile, dest1);
+ QRCodeUtils.graphicsGeneration(dest1, dest, text1);
+ org.apache.commons.io.FileUtils.forceDelete(dest1);
+ } else if (withText == 2) {
+ File dest1 = new File(destPath1);
+ org.apache.commons.io.FileUtils.copyFile(codeFile, dest1);
+ QRCodeUtils.graphicsGeneration2(dest1, dest, text1, text2);
+ org.apache.commons.io.FileUtils.forceDelete(dest1);
+ } else {
+ org.apache.commons.io.FileUtils.copyFile(codeFile, dest);
+ }
+ org.apache.commons.io.FileUtils.forceDelete(codeFile);
+ }
+
+ } catch (WxErrorException e) {
+ logger.error(e.getMessage());
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ }
+
+ try {
+ downFile(destPath, fileName, response, request);
+ org.apache.commons.io.FileUtils.forceDelete(dest);
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ }
+
+ }
+
+ private void downFile(String filePath, String filename, HttpServletResponse response, HttpServletRequest req) throws IOException {
+ try {
+ response.reset();
+ response.setContentType("application/octet-stream");
+ String agent = req.getHeader("user-agent");
+ if (agent.contains("Firefox")) {
+ response.setHeader("Content-disposition",
+ "attachment; filename="
+ + new String(filename.getBytes("GB2312"),"ISO-8859-1"));
+ } else {
+ response.setHeader("Content-disposition",
+ "attachment; filename="
+ + java.net.URLEncoder.encode(filename,"UTF-8"));
+ }
+ // 循环取出流中的数据
+ byte[] b = new byte[1024];
+ int len;
+ InputStream inStream = new FileInputStream(filePath);
+ while ((len = inStream.read(b)) > 0)
+ response.getOutputStream().write(b, 0, len);
+ inStream.close();
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ }
+ }
+
+
+}
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/controller/base/BaseController.java b/mallinkSysAdmin/src/main/java/com/iformall/controller/base/BaseController.java
new file mode 100644
index 000000000..2767ffb3b
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/controller/base/BaseController.java
@@ -0,0 +1,64 @@
+package com.iformall.controller.base;
+
+import java.beans.PropertyEditorSupport;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.iformall.domain.po.MallUserInfo;
+import com.iformall.shiro.UserSession;
+import com.iformall.utils.IPUtil;
+import org.apache.shiro.SecurityUtils;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+
+@RestController
+public class BaseController {
+
+ @InitBinder
+ public void InitBinder(WebDataBinder dataBinder) {
+ dataBinder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
+ public void setAsText(String value) {
+ try {
+ setValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value));
+ } catch(ParseException e) {
+ try {
+ setValue(new SimpleDateFormat("yyyy-MM-dd ").parse(value));
+ } catch (ParseException e1) {
+ setValue(null);
+ }
+ }
+ }
+
+ public String getAsText() {
+ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) getValue());
+ }
+
+ });
+ }
+ public MallUserInfo getUser(){
+ MallUserInfo user = (MallUserInfo) SecurityUtils.getSubject().getSession().getAttribute(UserSession.userInfo);
+ return user;
+ }
+
+ public Long getUserId(){
+ Long userId = (Long) SecurityUtils.getSubject().getSession().getAttribute(UserSession.userId);
+ return userId;
+ }
+
+ public String getTenantId(){
+ String tenantId = (String)SecurityUtils.getSubject().getSession().getAttribute(UserSession.tenantId);
+ return tenantId;
+ }
+
+ public String getIpAddr() {
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ String ipaddress = IPUtil.getIpAddr(request);
+ return ipaddress;
+ }
+}
diff --git a/mallinkSysAdmin/src/main/java/com/iformall/controller/basic/WxBrandController.java b/mallinkSysAdmin/src/main/java/com/iformall/controller/basic/WxBrandController.java
new file mode 100644
index 000000000..50ded68c6
--- /dev/null
+++ b/mallinkSysAdmin/src/main/java/com/iformall/controller/basic/WxBrandController.java
@@ -0,0 +1,102 @@
+package com.iformall.controller.basic;
+
+import com.github.pagehelper.PageInfo;
+import com.iformall.annotation.SystemControllerLog;
+import com.iformall.common.Result;
+import com.iformall.common.ResultData;
+import com.iformall.controller.base.BaseController;
+import com.iformall.domain.po.WxBrand;
+import com.iformall.service.WxBrandService;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+import static com.iformall.domain.po.WxBrand.Field.Id_DESC;
+
+/**
+ * @author gongbiao
+ */
+@RestController
+@RequestMapping("wxBrand")
+public class WxBrandController extends BaseController {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Autowired
+ private WxBrandService wxBrandService;
+
+
+ @GetMapping("list")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true),
+ @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)})
+ @SystemControllerLog(description = "品牌-列表")
+ public ResultData list(@ModelAttribute WxBrand wxBrand, Integer pageNum, Integer pageSize) {
+ logger.debug("[" + getIpAddr() + "] WxBrandController::list");
+ if (null == wxBrand) {
+ wxBrand = new WxBrand();
+ }
+ wxBrand.setSortColumns(Id_DESC);
+ final PageInfo page = wxBrandService.listAsPage(wxBrand, pageNum, pageSize);
+ return new ResultData(page);
+ }
+
+ @PostMapping("add")
+ @SystemControllerLog(description = "品牌-增加")
+ public ResultData add(@RequestBody WxBrand wxBrand) {
+ logger.debug("[" + getIpAddr() + "] WxBrandController::add");
+ wxBrand.setTenantId(getTenantId());
+ return wxBrandService.save(wxBrand);
+ }
+
+ @PostMapping("update")
+ @SystemControllerLog(description = "品牌-更新")
+ public ResultData update(@RequestBody WxBrand wxBrand) {
+ logger.debug("[" + getIpAddr() + "] WxBrandController::update");
+ wxBrand.setTenantId(getTenantId());
+ return wxBrandService.update(wxBrand);
+ }
+
+ @GetMapping("/del")
+ @ApiImplicitParam(name = "id", value = "id", dataType = "Long", paramType = "query", required = true)
+ @SystemControllerLog(description = "品牌-删除")
+ public ResultData delete(Long id) {
+ logger.debug("[" + getIpAddr() + "] WxBrandController::del");
+ wxBrandService.deleteById(id);
+ return new ResultData(Result.SUCCESS, "删除成功", null);
+ }
+
+ @GetMapping("/findById")
+ @ApiImplicitParam(name = "id", value = "id", dataType = "Long", paramType = "query", required = true)
+ @SystemControllerLog(description = "品牌-查找")
+ public ResultData findById(Long id) {
+ return new ResultData(Result.SUCCESS, "查询成功", wxBrandService.getById(id));
+ }
+
+ @GetMapping("/queryBrand")
+ @SystemControllerLog(description = "品牌-租户-全部")
+ public ResultData queryBrand() {
+ List