天择外汇模拟交易系统后端框架搭建

pull/1/head
陈沅 2 years ago
commit 7c16d404cc

33
.gitignore vendored

@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### 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/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar

@ -0,0 +1,46 @@
# 天择外汇模拟交易系统
## foreign_exchange_trading
**构建**\
环境要求JDK1.8及更高版本、Maven3.6+、postgresql。\
若项目依赖构建失败,请确认本地环境版本。\
JDK查看版本方式win+R进入CMD界面输入java -version即可查看\
Maven查看版本方式win+R进入CMD界面输入输入mvn -v即可查看\
maven构建进入idea Terminal界面运行命令 mvn clean install.等待项目build完成第一次构建系统可能耗时较长\
完成以上既可进行开发
**开发**
命名规范:类名采用大驼峰命名方式,方法名、变量名采用小驼峰方式.二者差异自行访问baidu.com查阅。\
**注代码注释需满足javadoc规范\** \
系统目录及代码归属约束:\
annotation系统切面文件。全局日志切面管理及接口权限控制文件.\
config整个系统配置文件如全局token校验swagger配置jpa配置及数据库方言配置.\
controller接口定义对外开放的接口文件请放置在该包每个模块有一个对应文件如对某模块新增接口请
放置到对应的controller文件内.\
entity实体类文件放置地址与数据库表字段对应调整数据库字段或新增表请移至改包对应的模块属性请放置于对应的类中.\
repository整个系统与数据库交互的文件放置于该包下如调整数据库语句请移至该包。注建议复杂查询及多表联查才用JPA原生SQL查询
简单查询请用Specification条件构造器.用法请参考service包下的子文件\
service子模块业务逻辑代码请放置于该包下。\
util系统用到的第三方工具文件请放置于该包如Excel导入导出、几何数据操作第三方API接入及结果解析、file文件处理全局异常定义等.\
**为防止系统结构混乱开发准备阶段请详细阅读开发规则及java文件归属规则。**
**运行**
设置ForeignExchangeTradingApplication为项目启动入口。Shift+F10启动. 注:必须完成上述开发节点下的项目构建工作才可启动,否则系统会报错
**接口预览及调用**
默认地址为localhost:8800端口号可自行更改
**测试**
后续团队将尽快整理和提供系统每一个子模块单元测试.
**发布**
CMD进入系统目录运行 mvn clean package命令移至target目录复制plantingInspect.jar文件\
windows发布cmd界面运行 java -jar plantingInspect.jar.\
linux发布请自行查阅baidu.com

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.sztzjy</groupId>
<artifactId>foreign_exchange_trading</artifactId>
<version>2.0-SNAPSHOT</version>
<name>foreign_exchange_trading</name>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.26</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.18</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
</dependency>
<!-- MySQL连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,13 @@
package com.sztzjy.forex.trading_trading;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ForeignExchangeTradingApplication {
public static void main(String[] args) {
SpringApplication.run(ForeignExchangeTradingApplication.class, args);
}
}

@ -0,0 +1,16 @@
package com.sztzjy.forex.trading_trading.annotation;
import java.lang.annotation.*;
/**
* 访 使Controller使访
*
* @author
*/
@Inherited
@Documented
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonymousAccess {
}

@ -0,0 +1,18 @@
package com.sztzjy.forex.trading_trading.config;
import org.springframework.stereotype.Component;
/**
*
*/
@Component
public class Constant {
/**
*
*/
public static final String AUTHORIZATION = "Authorization";
/**
* Basic
*/
public static final String BASIC = "Basic";
}

@ -0,0 +1,79 @@
package com.sztzjy.forex.trading_trading.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
/**
* applicationContextBean, .
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* applicationContextBean, .
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* ApplicationContext.
*/
private static void assertContextInjected() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
}
}
/**
* SpringContextHolderApplicationContextNull.
*/
private static void clearHolder() {
log.debug("清除SpringContextHolder中的ApplicationContext:"
+ applicationContext);
applicationContext = null;
}
@Override
public void destroy(){
SpringContextHolder.clearHolder();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringContextHolder.applicationContext != null) {
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
}
SpringContextHolder.applicationContext = applicationContext;
}
/**
*
*
* @param event
*/
public static void publishEvent(ApplicationEvent event) {
if (applicationContext == null) {
return;
}
applicationContext.publishEvent(event);
}
}

@ -0,0 +1,41 @@
package com.sztzjy.forex.trading_trading.config.exception;
/**
* 访
*
* @author
* @version 1.0.0
*/
public class UnAuthorizedException extends RuntimeException {
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public UnAuthorizedException(String message) {
super(message);
}
/**
* Constructs a new runtime exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public UnAuthorizedException(String message, Throwable cause) {
super(message, cause);
}
}

@ -0,0 +1,32 @@
package com.sztzjy.forex.trading_trading.config.exception.handler;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
*
* 访REST403 Forbidden
*
* @author
*/
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpStatus.FORBIDDEN.value());
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Content-Type", "application/json");
PrintWriter printWriter = response.getWriter();
printWriter.write("{\"code\":" + HttpStatus.FORBIDDEN.value() + ", \"msg\": \"权限不足\"}");
printWriter.flush();
}
}

@ -0,0 +1,39 @@
package com.sztzjy.forex.trading_trading.config.exception.handler;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* token
* 访REST401
*
* @author
*/
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
// 当用户尝试访问安全的REST资源而不提供任何凭据时将调用此方法发送401 响应
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Content-Type", "application/json");
Throwable cause = authException.getCause();
PrintWriter printWriter = response.getWriter();
if (cause instanceof InvalidTokenException) {
printWriter.write("{\"code\":" + HttpStatus.UNAUTHORIZED.value() + ",\"msg\":\"身份认证失败,无效或过期token\"}");
} else {
printWriter.write("{\"code\":" + HttpStatus.UNAUTHORIZED.value() + ",\"msg\":\"身份认证失败\"}");
}
printWriter.flush();
}
}

@ -0,0 +1,79 @@
package com.sztzjy.forex.trading_trading.config.exception.handler;
import com.sztzjy.forex.trading_trading.config.exception.UnAuthorizedException;
import com.sztzjy.forex.trading_trading.util.ResultEntity;
import com.sztzjy.forex.trading_trading.util.ThrowableUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
*
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResultEntity<String> illegalArgumentException(IllegalArgumentException e) {
log.error(ThrowableUtil.getStackTrace(e));
return new ResultEntity<>(HttpStatus.BAD_REQUEST, e.getMessage());
}
@ExceptionHandler(AccessDeniedException.class)
public ResultEntity<String> accessDeniedException(AccessDeniedException e) {
log.error(ThrowableUtil.getStackTrace(e));
return new ResultEntity<>(HttpStatus.FORBIDDEN, e.getMessage());
}
@ExceptionHandler(UnAuthorizedException.class)
public ResultEntity<String> UnAuthorizedException(UnAuthorizedException e) {
log.error(ThrowableUtil.getStackTrace(e));
return new ResultEntity<>(HttpStatus.UNAUTHORIZED, e.getMessage());
}
/**
*
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultEntity<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(ThrowableUtil.getStackTrace(e));
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
String message = objectError.getDefaultMessage();
if (objectError instanceof FieldError) {
message = ((FieldError) objectError).getField() + ": " + message;
}
return new ResultEntity<>(HttpStatus.BAD_REQUEST, message);
}
/**
*
*
* @param e
* @return /
*/
@ExceptionHandler(Throwable.class)
public ResultEntity<String> nullPointerException(Throwable e) {
log.error(ThrowableUtil.getStackTrace(e));
return new ResultEntity<>(HttpStatus.BAD_REQUEST, e.getMessage());
}
/**
* BadCredentialsException
*/
@ExceptionHandler(BadCredentialsException.class)
public ResultEntity<String> badCredentialsException(BadCredentialsException e) {
// 打印堆栈信息
String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage();
log.error(message);
return new ResultEntity<>(HttpStatus.BAD_REQUEST, message);
}
}

@ -0,0 +1,91 @@
package com.sztzjy.forex.trading_trading.config.security;
import cn.hutool.extra.servlet.ServletUtil;
import com.sztzjy.forex.trading_trading.config.Constant;
import com.sztzjy.forex.trading_trading.config.exception.UnAuthorizedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
/**
*
*
* @author
*/
public class AuthenticationFilter extends OncePerRequestFilter {
private final PathMatcher matcher = new AntPathMatcher();
private final TokenProvider tokenProvider;
public AuthenticationFilter(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String requestRri = request.getRequestURI();
if (requestRri.equals("/")) {
response.sendRedirect("/doc.html");
return;
}
if (!isExclude(request)) {
System.out.println("--------------------------------->>> " + LocalDateTime.now() + " ---ip:" + ServletUtil.getClientIP(request) + " requestUri:" + requestRri);
}
String token = request.getHeader(Constant.AUTHORIZATION);
if (token == null || token.equals("undefined") || token.equals("") || token.equals("null")) {
filterChain.doFilter(request, response);
return;
}
if (!StringUtils.startsWithIgnoreCase(token, "Bearer ")) {
throw new UnAuthorizedException("令牌错误: 缺失Bearer..");
}
JwtUser currentUser = tokenProvider.getClaims(token);
Authentication authentication = new UsernamePasswordAuthenticationToken(currentUser, "****", currentUser.getAuthorities());
request.getUserPrincipal();
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
}
/**
*
*/
private final static List<String> patterns = Arrays.asList(
"/swagger-resources/**",
"/doc.html",
"/webjars/**",
"/v2/**",
"/favicon.ico",
"/login",
"/druid/**"
);
/**
*
*
* @param request /
* @return true-
*/
private boolean isExclude(HttpServletRequest request) {
String requestURI = request.getRequestURI();
for (String pattern : patterns) {
if (matcher.match(pattern, requestURI)) {
return true;
}
}
return false;
}
}

@ -0,0 +1,48 @@
package com.sztzjy.forex.trading_trading.config.security;
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
/**
* jwt
*/
@Getter
@Setter
public class JwtUser implements UserDetails {
private String username;
private String password;
private String name;
private String userId;
private int roleId;
private int schoolId;
private int classId;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}

@ -0,0 +1,20 @@
package com.sztzjy.forex.trading_trading.config.security;
import org.springframework.stereotype.Component;
@Component
public class TokenProvider {
/**
* jwtToken
*
* @param jwtToken jwtToken
* @return jwt
*/
public JwtUser getClaims(String jwtToken) {
//todo 解析用户token
return null;
}
}

@ -0,0 +1,62 @@
package com.sztzjy.forex.trading_trading.config.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
*
*/
@Configuration
@EnableWebMvc
public class WebConfigurerAdapter implements WebMvcConfigurer {
@Resource
private StringHttpMessageConverter stringHttpMessageConverter;
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
@Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = new ReloadableResourceBundleMessageSource();
reloadableResourceBundleMessageSource.setBasename("classpath:messages");
return reloadableResourceBundleMessageSource;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0);
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (int i = 0; i < converters.size(); i++) {
if (converters.get(i) instanceof StringHttpMessageConverter) {
stringHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
converters.set(i, stringHttpMessageConverter);
}
}
}
}

@ -0,0 +1,112 @@
package com.sztzjy.forex.trading_trading.config.security;
import com.sztzjy.forex.trading_trading.annotation.AnonymousAccess;
import com.sztzjy.forex.trading_trading.config.SpringContextHolder;
import com.sztzjy.forex.trading_trading.config.exception.handler.CustomAccessDeniedHandler;
import com.sztzjy.forex.trading_trading.config.exception.handler.CustomAuthenticationEntryPoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* secret
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private TokenProvider tokenProvider;
@Resource
private CustomAccessDeniedHandler customAccessDeniedHandler;
@Resource
private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
RequestMappingHandlerMapping handlerMapping = SpringContextHolder.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
Set<String> anonymousUrls = discoveryAnonymousUrls(handlerMethods);
http
.addFilterBefore(new AuthenticationFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class)
// 禁用 CSRF
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
.accessDeniedHandler(customAccessDeniedHandler)
// 防止iframe 造成跨域
.and().headers().frameOptions().disable()
// 不创建会话
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// 所有请求都需要认证
.authorizeRequests()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/doc.html").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/v2/**").permitAll()
.antMatchers("/test/**").permitAll()
.antMatchers(anonymousUrls.toArray(new String[]{})).permitAll()
.anyRequest().authenticated();
}
/**
*
*
* @return {@link AuthenticationManager}
* @throws Exception /
*/
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
/**
* 访
*
* @param handlerMethodMap
* @return Mapping patterns
*/
private Set<String> discoveryAnonymousUrls(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {
Set<String> patterns = new HashSet<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = infoEntry.getValue();
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
if (Objects.nonNull(anonymousAccess)) {
assert infoEntry.getKey().getPatternsCondition() != null;
patterns.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
}
}
return patterns;
}
}

@ -0,0 +1,104 @@
package com.sztzjy.forex.trading_trading.config.swagger;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
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 javax.annotation.Resource;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* swagger 3.0
*
* @author
*/
@EnableSwagger2
@Configuration
@Profile({"dev", "pro", "test"})
public class Swagger2Config implements ApplicationListener<WebServerInitializedEvent> {
@Resource
private SwaggerProperties swaggerProperties;
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(swaggerProperties.getEnable())
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
// .globalRequestParameters(requestParameters())
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription())
.contact(new Contact(swaggerProperties.getContactName(), swaggerProperties.getContactAddress(), swaggerProperties.getContactEmail()))
.version(swaggerProperties.getVersion())
.build();
}
/**
*
*
* @return /
*/
private List<SecurityScheme> securitySchemes() {
List<SecurityScheme> schemes = new ArrayList<>();
SecurityScheme scheme = new ApiKey(swaggerProperties.getTokenHeader(), swaggerProperties.getTokenHeader(), In.HEADER.toValue());
schemes.add(scheme);
return schemes;
}
/**
*
*/
private List<SecurityContext> securityContexts() {
SecurityContext securityContext = SecurityContext.builder()
.securityReferences(Collections.singletonList(new SecurityReference(swaggerProperties.getTokenHeader(), new AuthorizationScope[]{new AuthorizationScope("global", "")})))
.build();
return Collections.singletonList(securityContext);
}
@Override
public void onApplicationEvent(WebServerInitializedEvent webServerInitializedEvent) {
try {
Logger logger = LoggerFactory.getLogger(Swagger2Config.class);
//获取IP
String hostAddress = Inet4Address.getLocalHost().getHostAddress();
//获取端口号
int port = webServerInitializedEvent.getWebServer().getPort();
//获取应用名
String applicationName = webServerInitializedEvent.getApplicationContext().getApplicationName();
logger.info("项目启动成功!接口文档地址: http://" + hostAddress + ":" + webServerInitializedEvent.getWebServer().getPort() + applicationName + "/doc.html#");
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}

@ -0,0 +1,115 @@
package com.sztzjy.forex.trading_trading.config.swagger;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author
*/
@Component
@ConfigurationProperties(prefix = "swagger")
public class SwaggerProperties {
/**
* swagger
*/
private Boolean enable;
/**
* KEY
*/
private String tokenHeader;
/**
*
*/
private String title;
/**
*
*/
private String description;
/**
*
*/
private String contactName;
/**
*
*/
private String contactAddress;
/**
*
*/
private String contactEmail;
/**
*
*/
private String version;
public Boolean getEnable() {
return enable;
}
public void setEnable(Boolean enable) {
this.enable = enable;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getContactName() {
return contactName;
}
public void setContactName(String contactName) {
this.contactName = contactName;
}
public String getContactAddress() {
return contactAddress;
}
public void setContactAddress(String contactAddress) {
this.contactAddress = contactAddress;
}
public String getContactEmail() {
return contactEmail;
}
public void setContactEmail(String contactEmail) {
this.contactEmail = contactEmail;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getTokenHeader() {
return tokenHeader;
}
public void setTokenHeader(String tokenHeader) {
this.tokenHeader = tokenHeader;
}
}

@ -0,0 +1,55 @@
package com.sztzjy.forex.trading_trading.util;
import lombok.Getter;
import org.springframework.http.HttpStatus;
/**
*
*/
@Getter
public class ResultDataEntity<T> {
/**
*
*/
private final Integer code;
/**
*
*/
// @JsonInclude(JsonInclude.Include.NON_NULL)
private String msg = null;
/**
*
*/
// @JsonInclude(JsonInclude.Include.NON_NULL)
private T data = null;
public ResultDataEntity(T data) {
this.code = HttpStatus.OK.value();
this.data = data;
}
public ResultDataEntity(HttpStatus status, T data) {
this.code = status.value();
this.data = data;
}
public ResultDataEntity(HttpStatus status, String msg, T data) {
this.code = status.value();
this.msg = msg;
this.data = data;
}
public ResultDataEntity(String msg) {
this.code = HttpStatus.OK.value();
this.msg = msg;
}
public ResultDataEntity(HttpStatus status, String msg) {
this.code = status.value();
this.msg = msg;
}
public ResultDataEntity(HttpStatus status) {
this.code = status.value();
}
}

@ -0,0 +1,38 @@
package com.sztzjy.forex.trading_trading.util;
import io.swagger.annotations.ApiModel;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
/**
* ResponseEntity
*
*/
@ApiModel("API返回对象")
@Getter
public class ResultEntity<T> extends ResponseEntity<ResultDataEntity<T>> {
public ResultEntity(T data) {
super(new ResultDataEntity<>(HttpStatus.OK, data), HttpStatus.OK);
}
public ResultEntity(HttpStatus status, T data) {
super(new ResultDataEntity<>(status, data), status);
}
public ResultEntity(HttpStatus status, String msg, T data) {
super(new ResultDataEntity<>(status, msg, data), status);
}
public ResultEntity(String msg) {
super(new ResultDataEntity<>(HttpStatus.OK, msg), HttpStatus.OK);
}
public ResultEntity(HttpStatus status, String msg) {
super(new ResultDataEntity<>(status, msg), status);
}
public ResultEntity(HttpStatus status) {
super(new ResultDataEntity<>(status), status);
}
}

@ -0,0 +1,23 @@
package com.sztzjy.forex.trading_trading.util;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
*
*
*
*/
public class ThrowableUtil {
/**
*
*/
public static String getStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {
throwable.printStackTrace(pw);
return sw.toString();
}
}
}

@ -0,0 +1,8 @@
spring:
datasource:
druid:
db-type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${DB_HOST:118.31.7.2}:${DB_PORT:3306}}/${DB_NAME:foreign_trading_system}?useSSL=false&serverTimezone=UTC
username: ${DB_USER:root}
password: ${DB_PWD:sztzjy2017}

@ -0,0 +1,82 @@
server:
port: 8800
servlet:
context-path: /
spring:
application:
name: trading_system
profiles:
active: dev
mvc:
pathmatch:
matching-strategy: ant_path_matcher
jackson:
time-zone: GMT+8
datasource:
druid:
# 初始连接数
initial-size: 5
# 最小连接数
min-idle: 15
# 最大连接数
max-active: 500
# 获取连接超时时间
max-wait: 5000
# 连接有效性检测时间
time-between-eviction-runs-millis: 60000
# 连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
# 连接在池中最大生存的时间
max-evictable-idle-time-millis: 900000
# 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除
test-while-idle: true
# 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个
test-on-borrow: false
# 是否在归还到池中前进行检验
test-on-return: false
# 检测连接是否有效
validation-query: select 'X'
# 配置监控统计
webStatFilter:
enabled: true
stat-view-servlet:
allow:
enabled: true
# 控制台管理用户名和密码
url-pattern: /druid/*
reset-enable: false
login-username: admin
login-password: 2023inspect
filter:
stat:
enabled: true
# 记录慢SQL
log-slow-sql: false
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
#配置 Jpa
jpa:
hibernate:
ddl-auto: update
open-in-view: true
show-sql: true
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
temp:
use_jdbc_metadata_defaults: false
database: mysql
swagger:
enable: true
tokenHeader: Authorization
title: 天择外汇模拟交易 • 接口文档
description: 天择外汇模拟交易WebAPI接口文档
contactName: 深圳天择教育科技有限公司
contactAddress: www.sztzjy.com
version: @project.version@

@ -0,0 +1,13 @@
package com.sztzjy.foreign_exchange_trading;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ForeignExchangeTradingApplicationTests {
@Test
void contextLoads() {
}
}
Loading…
Cancel
Save