Merge branch 'wvp-28181-2.0'

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
#	web_src/src/components/Login.vue
This commit is contained in:
648540858
2022-08-22 16:53:16 +08:00
146 changed files with 2878 additions and 17348 deletions

View File

@@ -9,6 +9,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.time.Instant;
import java.util.Map;
import java.util.Set;
@@ -25,20 +26,18 @@ public class DynamicTask {
private final Logger logger = LoggerFactory.getLogger(DynamicTask.class);
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
private final Map<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>();
private final Map<String, Runnable> runnableMap = new ConcurrentHashMap<>();
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler schedulerPool = new ThreadPoolTaskScheduler();
schedulerPool.setPoolSize(300);
schedulerPool.setWaitForTasksToCompleteOnShutdown(true);
schedulerPool.setAwaitTerminationSeconds(10);
return schedulerPool;
@PostConstruct
public void DynamicTask() {
threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(300);
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
threadPoolTaskScheduler.setAwaitTerminationSeconds(10);
threadPoolTaskScheduler.initialize();
}
/**

View File

@@ -0,0 +1,56 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局异常处理
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
private final static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 默认异常处理
* @param e 异常
* @return 统一返回结果
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public WVPResult<String> exceptionHandler(Exception e) {
logger.error("[全局异常] ", e);
return WVPResult.fail(ErrorCode.ERROR500.getCode(), e.getMessage());
}
/**
* 自定义异常处理, 处理controller中返回的错误
* @param e 异常
* @return 统一返回结果
*/
@ExceptionHandler(ControllerException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public WVPResult<String> exceptionHandler(ControllerException e) {
return WVPResult.fail(e.getCode(), e.getMsg());
}
/**
* 登陆失败
* @param e 异常
* @return 统一返回结果
*/
@ExceptionHandler(BadCredentialsException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public WVPResult<String> exceptionHandler(BadCredentialsException e) {
return WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMessage());
}
}

View File

@@ -0,0 +1,53 @@
package com.genersoft.iot.vmp.conf;
import com.alibaba.fastjson.JSON;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* 全局统一返回结果
* @author lin
*/
@RestControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(@NotNull MethodParameter returnType, @NotNull Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, @NotNull MethodParameter returnType, @NotNull MediaType selectedContentType, @NotNull Class<? extends HttpMessageConverter<?>> selectedConverterType, @NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) {
// 排除api文档的接口这个接口不需要统一
String[] excludePath = {"/v3/api-docs","/api/v1","/index/hook"};
for (String path : excludePath) {
if (request.getURI().getPath().startsWith(path)) {
return body;
}
}
if (body instanceof WVPResult) {
return body;
}
if (body instanceof ErrorCode) {
ErrorCode errorCode = (ErrorCode) body;
return new WVPResult<>(errorCode.getCode(), errorCode.getMsg(), null);
}
if (body instanceof String) {
return JSON.toJSONString(WVPResult.success(body));
}
return WVPResult.success(body);
}
}

View File

@@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.utils.DateUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.net.InetAddress;
@@ -88,7 +89,7 @@ public class MediaConfig{
}
public String getHookIp() {
if (StringUtils.isEmpty(hookIp)){
if (ObjectUtils.isEmpty(hookIp)){
return sipIp;
}else {
return hookIp;
@@ -162,7 +163,7 @@ public class MediaConfig{
}
public String getSdpIp() {
if (StringUtils.isEmpty(sdpIp)){
if (ObjectUtils.isEmpty(sdpIp)){
return ip;
}else {
if (isValidIPAddress(sdpIp)) {
@@ -181,7 +182,7 @@ public class MediaConfig{
}
public String getStreamIp() {
if (StringUtils.isEmpty(streamIp)){
if (ObjectUtils.isEmpty(streamIp)){
return ip;
}else {
return streamIp;

View File

@@ -14,6 +14,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.servlet.ServletException;
@@ -55,7 +56,7 @@ public class ProxyServletConfig {
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
if (mediaInfo != null) {
if (!StringUtils.isEmpty(queryStr)) {
if (!ObjectUtils.isEmpty(queryStr)) {
queryStr += "&secret=" + mediaInfo.getSecret();
}else {
queryStr = "secret=" + mediaInfo.getSecret();
@@ -146,7 +147,7 @@ public class ProxyServletConfig {
logger.error("[ZLM服务访问代理]错误处理url信息时未找到流媒体信息=>{}", requestURI);
return url;
}
if (!StringUtils.isEmpty(mediaInfo.getId())) {
if (!ObjectUtils.isEmpty(mediaInfo.getId())) {
url = url.replace(mediaInfo.getId() + "/", "");
}
return url.replace("default/", "");
@@ -173,7 +174,7 @@ public class ProxyServletConfig {
MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
String remoteHost = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getHttpPort());
if (mediaInfo != null) {
if (!StringUtils.isEmpty(queryStr)) {
if (!ObjectUtils.isEmpty(queryStr)) {
queryStr += "&remoteHost=" + remoteHost;
}else {
queryStr = "remoteHost=" + remoteHost;
@@ -265,7 +266,7 @@ public class ProxyServletConfig {
logger.error("[录像服务访问代理]错误处理url信息时未找到流媒体信息=>{}", requestURI);
return url;
}
if (!StringUtils.isEmpty(mediaInfo.getId())) {
if (!ObjectUtils.isEmpty(mediaInfo.getId())) {
url = url.replace(mediaInfo.getId() + "/", "");
}
return url.replace("default/", "");

View File

@@ -0,0 +1,89 @@
package com.genersoft.iot.vmp.conf;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.SpringDocConfigProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author lin
*/
@Configuration
public class SpringDocConfig {
@Value("${doc.enabled: true}")
private boolean enable;
@Bean
public OpenAPI springShopOpenApi() {
Contact contact = new Contact();
contact.setName("pan");
contact.setEmail("648540858@qq.com");
return new OpenAPI()
.info(new Info().title("WVP-PRO 接口文档")
.contact(contact)
.description("开箱即用的28181协议视频平台")
.version("v2.0")
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
}
/**
* 添加分组
* @return
*/
@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("1. 全部")
.packagesToScan("com.genersoft.iot.vmp.vmanager")
.build();
}
@Bean
public GroupedOpenApi publicApi2() {
return GroupedOpenApi.builder()
.group("2. 国标28181")
.packagesToScan("com.genersoft.iot.vmp.vmanager.gb28181")
.build();
}
@Bean
public GroupedOpenApi publicApi3() {
return GroupedOpenApi.builder()
.group("3. 拉流转发")
.packagesToScan("com.genersoft.iot.vmp.vmanager.streamProxy")
.build();
}
@Bean
public GroupedOpenApi publicApi4() {
return GroupedOpenApi.builder()
.group("4. 推流管理")
.packagesToScan("com.genersoft.iot.vmp.vmanager.streamPush")
.build();
}
@Bean
public GroupedOpenApi publicApi5() {
return GroupedOpenApi.builder()
.group("4. 服务管理")
.packagesToScan("com.genersoft.iot.vmp.vmanager.server")
.build();
}
@Bean
public GroupedOpenApi publicApi6() {
return GroupedOpenApi.builder()
.group("5. 用户管理")
.packagesToScan("com.genersoft.iot.vmp.vmanager.user")
.build();
}
}

View File

@@ -1,117 +0,0 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Value;
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.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
@Configuration
public class Swagger3Config {
@Value("${swagger-ui.enabled: true}")
private boolean enable;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("1. 全部")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createRestGBApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("2. 国标28181")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.gb28181"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createRestONVIFApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("3. ONVIF")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.onvif"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createRestStreamProxyApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("4. 拉流转发")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.streamProxy"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createRestStreamPushApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("5. 推流管理")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.streamPush"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createServerApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("6. 服务管理")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.server"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createUserApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("7. 用户管理")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.user"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(enable);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("WVP-PRO 接口文档")
.description("更多请咨询服务开发者(https://github.com/648540858/wvp-GB28181-pro)。")
.contact(new Contact("648540858", "648540858", "648540858@qq.com"))
.version("2.0")
.build();
}
}

View File

@@ -0,0 +1,37 @@
package com.genersoft.iot.vmp.conf.exception;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
/**
* 自定义异常controller出现错误时直接抛出异常由全局异常捕获并返回结果
*/
public class ControllerException extends RuntimeException{
private int code;
private String msg;
public ControllerException(int code, String msg) {
this.code = code;
this.msg = msg;
}
public ControllerException(ErrorCode errorCode) {
this.code = errorCode.getCode();
this.msg = errorCode.getMsg();
}
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;
}
}

View File

@@ -1,86 +1,87 @@
package com.genersoft.iot.vmp.conf;
import com.alibaba.fastjson.parser.ParserConfig;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
/**
* @description:Redis中间件配置类使用spring-data-redis集成自动从application.yml中加载redis配置
* @author: swwheihei
* @date: 2019年5月30日 上午10:58:25
*
*/
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private RedisGpsMsgListener redisGPSMsgListener;
@Autowired
private RedisAlarmMsgListener redisAlarmMsgListener;
@Autowired
private RedisStreamMsgListener redisStreamMsgListener;
@Autowired
private RedisGbPlayMsgListener redisGbPlayMsgListener;
@Autowired
private RedisPushStreamStatusMsgListener redisPushStreamStatusMsgListener;
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
// 使用fastJson序列化
FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
// value值的序列化采用fastJsonRedisSerializer
redisTemplate.setValueSerializer(fastJsonRedisSerializer);
redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
// 全局开启AutoType不建议使用
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// 建议使用这种方式小范围指定白名单需要序列化的类
// ParserConfig.getGlobalInstance().addAccept("com.avatar");
// key的序列化采用StringRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
/**
* redis消息监听器容器 可以添加多个监听不同话题的redis监听器只需要把消息监听器和相应的消息订阅处理器绑定该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
*
* @param connectionFactory
* @return
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(redisGPSMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_GPS));
container.addMessageListener(redisAlarmMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM_RECEIVE));
container.addMessageListener(redisStreamMsgListener, new PatternTopic(VideoManagerConstants.WVP_MSG_STREAM_CHANGE_PREFIX + "PUSH"));
container.addMessageListener(redisGbPlayMsgListener, new PatternTopic(RedisGbPlayMsgListener.WVP_PUSH_STREAM_KEY));
container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE));
return container;
}
}
package com.genersoft.iot.vmp.conf.redis;
import com.alibaba.fastjson.parser.ParserConfig;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.service.impl.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
/**
* @description:Redis中间件配置类使用spring-data-redis集成自动从application.yml中加载redis配置
* @author: swwheihei
* @date: 2019年5月30日 上午10:58:25
*
*/
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private RedisGpsMsgListener redisGPSMsgListener;
@Autowired
private RedisAlarmMsgListener redisAlarmMsgListener;
@Autowired
private RedisStreamMsgListener redisStreamMsgListener;
@Autowired
private RedisGbPlayMsgListener redisGbPlayMsgListener;
@Autowired
private RedisPushStreamStatusMsgListener redisPushStreamStatusMsgListener;
@Autowired
private RedisPushStreamListMsgListener redisPushStreamListMsgListener;
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
// 使用fastJson序列化
FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
// value值的序列化采用fastJsonRedisSerializer
redisTemplate.setValueSerializer(fastJsonRedisSerializer);
redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
// 全局开启AutoType建议使用
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// key的序列化采用StringRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
/**
* redis消息监听器容器 可以添加多个监听不同话题的redis监听器只需要把消息监听器和相应的消息订阅处理器绑定该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
*
* @param connectionFactory
* @return
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(redisGPSMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_GPS));
container.addMessageListener(redisAlarmMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM_RECEIVE));
container.addMessageListener(redisStreamMsgListener, new PatternTopic(VideoManagerConstants.WVP_MSG_STREAM_CHANGE_PREFIX + "PUSH"));
container.addMessageListener(redisGbPlayMsgListener, new PatternTopic(RedisGbPlayMsgListener.WVP_PUSH_STREAM_KEY));
container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE));
container.addMessageListener(redisPushStreamListMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_LIST_CHANGE));
return container;
}
}

View File

@@ -91,6 +91,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.antMatchers("/webjars/**")
.antMatchers("/swagger-resources/**")
.antMatchers("/v3/api-docs/**")
.antMatchers("/favicon.ico")
.antMatchers("/js/**");
List<String> interfaceAuthenticationExcludes = userSetting.getInterfaceAuthenticationExcludes();
for (String interfaceAuthenticationExclude : interfaceAuthenticationExcludes) {