Compare commits
	
		
			4 Commits 
		
	
	
		
			5e5fb9a07d
			...
			3b598b0e81
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								 | 
						3b598b0e81 | 2 years ago | 
| 
							
							
								 | 
						077751021e | 2 years ago | 
| 
							
							
								 | 
						7e63ad937d | 2 years ago | 
| 
							
							
								 | 
						e044f02d32 | 2 years ago | 
				 19 changed files with 887 additions and 112 deletions
			
			
		@ -0,0 +1,18 @@ | 
				
			|||||||
 | 
					package cn.soul2.jyjc.admin.annotation; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.lang.annotation.ElementType; | 
				
			||||||
 | 
					import java.lang.annotation.Retention; | 
				
			||||||
 | 
					import java.lang.annotation.RetentionPolicy; | 
				
			||||||
 | 
					import java.lang.annotation.Target; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * 跳过加解密 | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * @author Soul2 | 
				
			||||||
 | 
					 * @date 2024-04-08 | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					@Target({ElementType.METHOD, ElementType.TYPE}) | 
				
			||||||
 | 
					@Retention(RetentionPolicy.RUNTIME) | 
				
			||||||
 | 
					public @interface SkinEncrypt { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} | 
				
			||||||
@ -1,28 +0,0 @@ | 
				
			|||||||
package cn.soul2.jyjc.admin.config; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.springframework.beans.factory.annotation.Value; | 
					 | 
				
			||||||
import org.springframework.context.annotation.Configuration; | 
					 | 
				
			||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry; | 
					 | 
				
			||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** | 
					 | 
				
			||||||
 * @author Soul2 | 
					 | 
				
			||||||
 * @date 2024-03-25 | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
@Configuration | 
					 | 
				
			||||||
public class CorsConfig implements WebMvcConfigurer { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Value("${cors.allow-origin}") | 
					 | 
				
			||||||
    private String[] allowOrigin; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override | 
					 | 
				
			||||||
    public void addCorsMappings(CorsRegistry registry) { | 
					 | 
				
			||||||
        registry.addMapping("/**") | 
					 | 
				
			||||||
                .allowedHeaders("*") | 
					 | 
				
			||||||
                .allowedOrigins(allowOrigin) | 
					 | 
				
			||||||
                .allowCredentials(true) | 
					 | 
				
			||||||
                .allowedMethods("POST") | 
					 | 
				
			||||||
                .maxAge(3600); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -0,0 +1,41 @@ | 
				
			|||||||
 | 
					package cn.soul2.jyjc.admin.config; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.soul2.jyjc.admin.filter.ReplaceStreamFilter; | 
				
			||||||
 | 
					import org.springframework.boot.web.servlet.FilterRegistrationBean; | 
				
			||||||
 | 
					import org.springframework.context.annotation.Bean; | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.servlet.Filter; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * @author Soul2 | 
				
			||||||
 | 
					 * @description 过滤器配置类 | 
				
			||||||
 | 
					 * @date 2024-04-08 | 
				
			||||||
 | 
					 * <p>照抄自 <a href="https://blog.csdn.net/shaoduo/article/details/122322578">Shao duo</a></p> | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					@Configuration | 
				
			||||||
 | 
					public class FilterConfig { | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 注册过滤器 | 
				
			||||||
 | 
					     * | 
				
			||||||
 | 
					     * @return FilterRegistrationBean | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    @Bean | 
				
			||||||
 | 
					    public FilterRegistrationBean someFilterRegistration() { | 
				
			||||||
 | 
					        FilterRegistrationBean registration = new FilterRegistrationBean(); | 
				
			||||||
 | 
					        registration.setFilter(replaceStreamFilter()); | 
				
			||||||
 | 
					        registration.addUrlPatterns("/*"); | 
				
			||||||
 | 
					        registration.setName("streamFilter"); | 
				
			||||||
 | 
					        return registration; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 实例化StreamFilter | 
				
			||||||
 | 
					     * | 
				
			||||||
 | 
					     * @return Filter | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    @Bean(name = "replaceStreamFilter") | 
				
			||||||
 | 
					    public Filter replaceStreamFilter() { | 
				
			||||||
 | 
					        return new ReplaceStreamFilter(); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,60 @@ | 
				
			|||||||
 | 
					package cn.soul2.jyjc.admin.filter; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.soul2.jyjc.admin.utils.EncryptUtils; | 
				
			||||||
 | 
					import lombok.extern.slf4j.Slf4j; | 
				
			||||||
 | 
					import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.servlet.*; | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletRequest; | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletResponse; | 
				
			||||||
 | 
					import java.io.IOException; | 
				
			||||||
 | 
					import java.io.PrintWriter; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * @author shaoduo | 
				
			||||||
 | 
					 * @description 替换HttpServletRequest | 
				
			||||||
 | 
					 * @since 1.0 | 
				
			||||||
 | 
					 **/ | 
				
			||||||
 | 
					@Slf4j | 
				
			||||||
 | 
					public class ReplaceStreamFilter implements Filter { | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public void init(FilterConfig filterConfig) throws ServletException { | 
				
			||||||
 | 
					        log.info("StreamFilter初始化..."); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { | 
				
			||||||
 | 
					        //如果是文件上传则会报错可以判断是否是文件上传不读取流即可
 | 
				
			||||||
 | 
					        if (ServletFileUpload.isMultipartContent((HttpServletRequest) request)) { | 
				
			||||||
 | 
					            chain.doFilter(request, response); | 
				
			||||||
 | 
					        } else if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) request).getMethod())) { | 
				
			||||||
 | 
					            chain.doFilter(request, response); | 
				
			||||||
 | 
					        } else { | 
				
			||||||
 | 
					            ServletRequest requestWrapper = new ShaoduoRequestWrapper((HttpServletRequest) request); | 
				
			||||||
 | 
					//            System.out.printf("ReplaceStreamFilter触发, Method: %s, URI: %s%n", ((HttpServletRequest) request).getMethod(), ((HttpServletRequest) request).getRequestURI());
 | 
				
			||||||
 | 
					            HttpServletResponse httpResponse = (HttpServletResponse) response; | 
				
			||||||
 | 
					            Soul2ResponseWrapper soul2ResponseWrapper = new Soul2ResponseWrapper(httpResponse); | 
				
			||||||
 | 
					            chain.doFilter(requestWrapper, soul2ResponseWrapper); | 
				
			||||||
 | 
					            try { | 
				
			||||||
 | 
					                byte[] data = soul2ResponseWrapper.getResponseData(); | 
				
			||||||
 | 
					                log.debug("原始返回 -> " + new String(data)); | 
				
			||||||
 | 
					                String encryptBody = EncryptUtils.encrypt(new String(data)); | 
				
			||||||
 | 
					                log.debug("加密返回 -> " + encryptBody); | 
				
			||||||
 | 
					                soul2ResponseWrapper.setHeader("encrypt", "1"); | 
				
			||||||
 | 
					                soul2ResponseWrapper.setHeader("Access-Control-Expose-Headers", "encrypt"); | 
				
			||||||
 | 
					                PrintWriter out = response.getWriter(); | 
				
			||||||
 | 
					                out.print(encryptBody); | 
				
			||||||
 | 
					                out.flush(); | 
				
			||||||
 | 
					                out.close(); | 
				
			||||||
 | 
					            } catch (Exception e) { | 
				
			||||||
 | 
					                e.printStackTrace(); | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public void destroy() { | 
				
			||||||
 | 
					        log.info("StreamFilter销毁..."); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,130 @@ | 
				
			|||||||
 | 
					package cn.soul2.jyjc.admin.filter; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import lombok.extern.slf4j.Slf4j; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.servlet.ReadListener; | 
				
			||||||
 | 
					import javax.servlet.ServletInputStream; | 
				
			||||||
 | 
					import javax.servlet.ServletRequest; | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletRequest; | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletRequestWrapper; | 
				
			||||||
 | 
					import java.io.*; | 
				
			||||||
 | 
					import java.nio.charset.Charset; | 
				
			||||||
 | 
					import java.nio.charset.StandardCharsets; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * @author shaoduo | 
				
			||||||
 | 
					 * @description 包装HttpServletRequest,目的是让其输入流可重复读 | 
				
			||||||
 | 
					 * @since <a href="https://blog.csdn.net/shaoduo/article/details/122322578">shaoduo</a> | 
				
			||||||
 | 
					 **/ | 
				
			||||||
 | 
					@Slf4j | 
				
			||||||
 | 
					public class ShaoduoRequestWrapper extends HttpServletRequestWrapper { | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 存储body数据的容器 | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    private byte[] body; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ShaoduoRequestWrapper(HttpServletRequest request) { | 
				
			||||||
 | 
					        super(request); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 将body数据存储起来
 | 
				
			||||||
 | 
					        String bodyStr = getBodyString(request); | 
				
			||||||
 | 
					        body = bodyStr.getBytes(Charset.defaultCharset()); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 获取请求Body | 
				
			||||||
 | 
					     * | 
				
			||||||
 | 
					     * @param request request | 
				
			||||||
 | 
					     * @return String | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public String getBodyString(final ServletRequest request) { | 
				
			||||||
 | 
					        try { | 
				
			||||||
 | 
					            return inputStream2String(request.getInputStream()); | 
				
			||||||
 | 
					        } catch (IOException e) { | 
				
			||||||
 | 
					            log.error("", e); | 
				
			||||||
 | 
					            throw new RuntimeException(e); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 获取请求Body | 
				
			||||||
 | 
					     * | 
				
			||||||
 | 
					     * @return String | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public String getBodyString() throws IOException { | 
				
			||||||
 | 
					        InputStream inputStream = new ByteArrayInputStream(body); | 
				
			||||||
 | 
					        return inputStream2String(inputStream); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 修改body 将json 重新设置成body | 
				
			||||||
 | 
					     * | 
				
			||||||
 | 
					     * @param val | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public void setBody(String val) { | 
				
			||||||
 | 
					        body = val.getBytes(StandardCharsets.UTF_8); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 将inputStream里的数据读取出来并转换成字符串 | 
				
			||||||
 | 
					     * | 
				
			||||||
 | 
					     * @param inputStream inputStream | 
				
			||||||
 | 
					     * @return String | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    private String inputStream2String(InputStream inputStream) throws IOException { | 
				
			||||||
 | 
					        StringBuilder sb = new StringBuilder(); | 
				
			||||||
 | 
					        BufferedReader reader = null; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try { | 
				
			||||||
 | 
					            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset())); | 
				
			||||||
 | 
					            String line; | 
				
			||||||
 | 
					            while ((line = reader.readLine()) != null) { | 
				
			||||||
 | 
					                sb.append(line); | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					        } catch (IOException e) { | 
				
			||||||
 | 
					            log.error("", e); | 
				
			||||||
 | 
					            throw new RuntimeException(e); | 
				
			||||||
 | 
					        } finally { | 
				
			||||||
 | 
					            if (reader != null) { | 
				
			||||||
 | 
					                try { | 
				
			||||||
 | 
					                    reader.close(); | 
				
			||||||
 | 
					                } catch (IOException e) { | 
				
			||||||
 | 
					                    log.error("", e); | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        return sb.toString(); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public BufferedReader getReader() throws IOException { | 
				
			||||||
 | 
					        return new BufferedReader(new InputStreamReader(getInputStream())); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public ServletInputStream getInputStream() { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final ByteArrayInputStream inputStream = new ByteArrayInputStream(body); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new ServletInputStream() { | 
				
			||||||
 | 
					            @Override | 
				
			||||||
 | 
					            public int read() { | 
				
			||||||
 | 
					                return inputStream.read(); | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @Override | 
				
			||||||
 | 
					            public boolean isFinished() { | 
				
			||||||
 | 
					                return false; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @Override | 
				
			||||||
 | 
					            public boolean isReady() { | 
				
			||||||
 | 
					                return false; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @Override | 
				
			||||||
 | 
					            public void setReadListener(ReadListener readListener) { | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					        }; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,120 @@ | 
				
			|||||||
 | 
					package cn.soul2.jyjc.admin.filter; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import lombok.SneakyThrows; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.servlet.ServletOutputStream; | 
				
			||||||
 | 
					import javax.servlet.WriteListener; | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletResponse; | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletResponseWrapper; | 
				
			||||||
 | 
					import java.io.*; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * @author Soul2 | 
				
			||||||
 | 
					 * @description 包装ServletResponse, 照抄自 <a href="https://blog.csdn.net/temp_44/article/details/107762290">temp_44</a> | 
				
			||||||
 | 
					 * @date 2024-04-15 | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					public class Soul2ResponseWrapper extends HttpServletResponseWrapper { | 
				
			||||||
 | 
					    private ByteArrayOutputStream buffer = null; | 
				
			||||||
 | 
					    private ServletOutputStream out = null; | 
				
			||||||
 | 
					    private PrintWriter writer = null; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Soul2ResponseWrapper(HttpServletResponse resp) throws IOException { | 
				
			||||||
 | 
					        super(resp); | 
				
			||||||
 | 
					        // 真正存储数据的流
 | 
				
			||||||
 | 
					        buffer = new ByteArrayOutputStream(); | 
				
			||||||
 | 
					        out = new WapperedOutputStream(buffer); | 
				
			||||||
 | 
					        writer = new PrintWriter(new OutputStreamWriter(buffer, | 
				
			||||||
 | 
					                this.getCharacterEncoding())); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 重载父类获取outputstream的方法 | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public ServletOutputStream getOutputStream() throws IOException { | 
				
			||||||
 | 
					        return out; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 重载父类获取writer的方法 | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public PrintWriter getWriter() throws UnsupportedEncodingException { | 
				
			||||||
 | 
					        return writer; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * The default behavior of this method is to call | 
				
			||||||
 | 
					     * setCharacterEncoding(String charset) on the wrapped response object. | 
				
			||||||
 | 
					     * | 
				
			||||||
 | 
					     * @param charset | 
				
			||||||
 | 
					     * @since 2.4 | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    @SneakyThrows | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public void setCharacterEncoding(String charset) { | 
				
			||||||
 | 
					        super.setCharacterEncoding(charset); | 
				
			||||||
 | 
					        writer = new PrintWriter(new OutputStreamWriter(buffer, | 
				
			||||||
 | 
					                this.getCharacterEncoding())); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 重载父类获取flushBuffer的方法 | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public void flushBuffer() throws IOException { | 
				
			||||||
 | 
					        if (out != null) { | 
				
			||||||
 | 
					            out.flush(); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        if (writer != null) { | 
				
			||||||
 | 
					            writer.flush(); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public void reset() { | 
				
			||||||
 | 
					        buffer.reset(); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public byte[] getResponseData() throws IOException { | 
				
			||||||
 | 
					        flushBuffer(); | 
				
			||||||
 | 
					        return buffer.toByteArray(); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 内部类,对ServletOutputStream进行包装 | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    private class WapperedOutputStream extends ServletOutputStream { | 
				
			||||||
 | 
					        private ByteArrayOutputStream bos = null; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public WapperedOutputStream(ByteArrayOutputStream stream) | 
				
			||||||
 | 
					                throws IOException { | 
				
			||||||
 | 
					            bos = stream; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override | 
				
			||||||
 | 
					        public void write(int b) throws IOException { | 
				
			||||||
 | 
					            bos.write(b); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override | 
				
			||||||
 | 
					        public void write(byte[] b) throws IOException { | 
				
			||||||
 | 
					            bos.write(b, 0, b.length); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override | 
				
			||||||
 | 
					        public boolean isReady() { | 
				
			||||||
 | 
					            // TODO Auto-generated method stub
 | 
				
			||||||
 | 
					            return false; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override | 
				
			||||||
 | 
					        public void setWriteListener(WriteListener writeListener) { | 
				
			||||||
 | 
					            // TODO Auto-generated method stub
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,140 @@ | 
				
			|||||||
 | 
					package cn.soul2.jyjc.admin.interceptor; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.soul2.jyjc.admin.annotation.SkinEncrypt; | 
				
			||||||
 | 
					import cn.soul2.jyjc.admin.annotation.SkinLogin; | 
				
			||||||
 | 
					import cn.soul2.jyjc.admin.bean.UserLoginStatusBean; | 
				
			||||||
 | 
					import cn.soul2.jyjc.admin.filter.ShaoduoRequestWrapper; | 
				
			||||||
 | 
					import cn.soul2.jyjc.admin.service.IUserService; | 
				
			||||||
 | 
					import cn.soul2.jyjc.admin.utils.EncryptUtils; | 
				
			||||||
 | 
					import cn.soul2.jyjc.admin.vo.base.Back; | 
				
			||||||
 | 
					import com.alibaba.fastjson.JSON; | 
				
			||||||
 | 
					import com.alibaba.fastjson.JSONObject; | 
				
			||||||
 | 
					import com.fasterxml.jackson.databind.ObjectMapper; | 
				
			||||||
 | 
					import lombok.extern.slf4j.Slf4j; | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Autowired; | 
				
			||||||
 | 
					import org.springframework.web.method.HandlerMethod; | 
				
			||||||
 | 
					import org.springframework.web.servlet.HandlerInterceptor; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.annotation.Resource; | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletRequest; | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletResponse; | 
				
			||||||
 | 
					import java.io.PrintWriter; | 
				
			||||||
 | 
					import java.lang.reflect.Method; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * Token拦截器 | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * @author Soul2 | 
				
			||||||
 | 
					 * @date 2024-04-02 15:31 | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					@Slf4j | 
				
			||||||
 | 
					public class FinallyInterceptor implements HandlerInterceptor { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Resource | 
				
			||||||
 | 
					    private UserLoginStatusBean userLoginStatusBean; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Autowired | 
				
			||||||
 | 
					    private IUserService userService; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private boolean load = true; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void loadUserLoginStatus() { | 
				
			||||||
 | 
					        userLoginStatusBean.loadUserLoginStatus(userService.getLoginedUser()); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override | 
				
			||||||
 | 
					    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | 
				
			||||||
 | 
					        if (load) { | 
				
			||||||
 | 
					            loadUserLoginStatus(); | 
				
			||||||
 | 
					            load = false; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        boolean pass = false; | 
				
			||||||
 | 
					        // 允许OPTIONS请求通过
 | 
				
			||||||
 | 
					        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { | 
				
			||||||
 | 
					            return true; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        // 如果不是映射到方法直接通过
 | 
				
			||||||
 | 
					        if (!(handler instanceof HandlerMethod)) { | 
				
			||||||
 | 
					            return true; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        HandlerMethod handlerMethod = (HandlerMethod) handler; | 
				
			||||||
 | 
					        Method method = handlerMethod.getMethod(); | 
				
			||||||
 | 
					        String httpMethod = request.getMethod(); | 
				
			||||||
 | 
					        SkinEncrypt skinEncrypt = handlerMethod.getMethodAnnotation(SkinEncrypt.class); | 
				
			||||||
 | 
					        // 检查方法上是否存在SkinLogin注解
 | 
				
			||||||
 | 
					        boolean hasSkinLogin = handlerMethod.getMethodAnnotation(SkinLogin.class) != null; | 
				
			||||||
 | 
					        // 从请求头中获取 token
 | 
				
			||||||
 | 
					        String token = request.getHeader("jyjc-Token"); | 
				
			||||||
 | 
					        try { | 
				
			||||||
 | 
					        /* | 
				
			||||||
 | 
					            加解密 | 
				
			||||||
 | 
					         */ | 
				
			||||||
 | 
					            // 不拦截get请求
 | 
				
			||||||
 | 
					            if ("GET".equals(httpMethod)) { | 
				
			||||||
 | 
					                pass = true; | 
				
			||||||
 | 
					                // 如果是post请求且是json
 | 
				
			||||||
 | 
					            } else if ("POST".equals(httpMethod)) { | 
				
			||||||
 | 
					                // 如果类型为空就放行
 | 
				
			||||||
 | 
					                if (request.getContentType() == null) { | 
				
			||||||
 | 
					                    pass = true; | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            // 跳过使用 @SkinEncrypt 的情况
 | 
				
			||||||
 | 
					            if (skinEncrypt != null) { | 
				
			||||||
 | 
					                pass = true; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!pass) { | 
				
			||||||
 | 
					                ShaoduoRequestWrapper shaoduoRequestWrapper; | 
				
			||||||
 | 
					                try { | 
				
			||||||
 | 
					                    shaoduoRequestWrapper = (ShaoduoRequestWrapper) request; | 
				
			||||||
 | 
					                } catch (Exception e) { | 
				
			||||||
 | 
					                    System.out.printf("request.ClassTypeError: %s%n", request.getClass().getName()); | 
				
			||||||
 | 
					                    return true; | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					                String sourceParamBody = shaoduoRequestWrapper.getBodyString(); | 
				
			||||||
 | 
					                JSONObject obj = JSON.parseObject(EncryptUtils.decrypt(sourceParamBody)); | 
				
			||||||
 | 
					                String afterBody = JSONObject.toJSONString(obj); | 
				
			||||||
 | 
					                shaoduoRequestWrapper.setBody(afterBody); | 
				
			||||||
 | 
					                log.debug(String.format("解密: %s -> %s", sourceParamBody, afterBody)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* token验证 */ | 
				
			||||||
 | 
					            if (hasSkinLogin) { | 
				
			||||||
 | 
					                // 跳过使用 @SkinLogin 的情况
 | 
				
			||||||
 | 
					                pass = true; | 
				
			||||||
 | 
					            } else { | 
				
			||||||
 | 
					                // 验证token
 | 
				
			||||||
 | 
					                // 检查 token 是否存在并且有效
 | 
				
			||||||
 | 
					                if (token == null) { | 
				
			||||||
 | 
					                    // 没有Token,拒绝请求
 | 
				
			||||||
 | 
					                    response.setStatus(40401); | 
				
			||||||
 | 
					                    pass = false; | 
				
			||||||
 | 
					                } else if (userLoginStatusBean != null) { | 
				
			||||||
 | 
					                    if (!userLoginStatusBean.containsToken(token)) { | 
				
			||||||
 | 
					                        // Token 无效,拒绝请求
 | 
				
			||||||
 | 
					                        response.setContentType("application/json"); | 
				
			||||||
 | 
					                        Back<String> back = new Back<String>().setCode(40401).setMessage("Token invalid!"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        // 转换为 JSON 字符串
 | 
				
			||||||
 | 
					                        ObjectMapper objectMapper = new ObjectMapper(); | 
				
			||||||
 | 
					                        String responseBody = objectMapper.writeValueAsString(back); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        // 输出错误信息到响应中
 | 
				
			||||||
 | 
					                        PrintWriter writer = response.getWriter(); | 
				
			||||||
 | 
					                        writer.print(responseBody); | 
				
			||||||
 | 
					                        writer.flush(); | 
				
			||||||
 | 
					                        pass = false; | 
				
			||||||
 | 
					                    } else { | 
				
			||||||
 | 
					                        // token存在, 通过拦截器
 | 
				
			||||||
 | 
					                        pass = true; | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					        } catch (Exception e) { | 
				
			||||||
 | 
					            throw new RuntimeException(e); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        return pass; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -1,63 +0,0 @@ | 
				
			|||||||
package cn.soul2.jyjc.admin.interceptor; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import cn.soul2.jyjc.admin.annotation.SkinLogin; | 
					 | 
				
			||||||
import cn.soul2.jyjc.admin.config.UserLoginStatusBean; | 
					 | 
				
			||||||
import org.springframework.beans.factory.annotation.Autowired; | 
					 | 
				
			||||||
import org.springframework.web.method.HandlerMethod; | 
					 | 
				
			||||||
import org.springframework.web.servlet.HandlerInterceptor; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.servlet.http.HttpServletRequest; | 
					 | 
				
			||||||
import javax.servlet.http.HttpServletResponse; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** | 
					 | 
				
			||||||
 * @author Soul2 | 
					 | 
				
			||||||
 * @date 2024-04-02 15:31 | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class TokenInterceptor implements HandlerInterceptor { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Autowired | 
					 | 
				
			||||||
    private UserLoginStatusBean userLoginStatusBean; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override | 
					 | 
				
			||||||
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | 
					 | 
				
			||||||
        // 允许OPTIONS请求通过
 | 
					 | 
				
			||||||
        if (isCorsRequest(request)) { | 
					 | 
				
			||||||
            return true; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 跳过登录
 | 
					 | 
				
			||||||
        // 如果处理器是一个方法处理器
 | 
					 | 
				
			||||||
        if (handler instanceof HandlerMethod) { | 
					 | 
				
			||||||
            HandlerMethod handlerMethod = (HandlerMethod) handler; | 
					 | 
				
			||||||
            // 检查方法上是否存在SkinLogin注解
 | 
					 | 
				
			||||||
            if (handlerMethod.getMethod().isAnnotationPresent(SkinLogin.class)) { | 
					 | 
				
			||||||
                // 如果存在,绕过拦截器
 | 
					 | 
				
			||||||
                return true; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
        // 验证token
 | 
					 | 
				
			||||||
        // 从请求头中获取 token
 | 
					 | 
				
			||||||
        String token = request.getHeader("jyjc-Token"); | 
					 | 
				
			||||||
        // 检查 token 是否存在并且有效,这里可以根据实际情况自行实现验证逻辑
 | 
					 | 
				
			||||||
        if (token != null && isValidToken(token)) { | 
					 | 
				
			||||||
            // Token 有效,允许请求通过
 | 
					 | 
				
			||||||
            return true; | 
					 | 
				
			||||||
        } else { | 
					 | 
				
			||||||
            // Token 无效,拒绝请求,可以返回特定的响应状态码,例如 401 Unauthorized
 | 
					 | 
				
			||||||
            response.setStatus(40401); | 
					 | 
				
			||||||
            return false; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private boolean isValidToken(String token) { | 
					 | 
				
			||||||
        // 实现 token 验证逻辑,例如验证 token 的签名或者在数据库中验证 token 的有效性
 | 
					 | 
				
			||||||
        return userLoginStatusBean.containsToken(token); | 
					 | 
				
			||||||
        // 返回 true 表示 token 有效,返回 false 表示 token 无效
 | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private boolean isCorsRequest(HttpServletRequest request) { | 
					 | 
				
			||||||
        // 检查请求头中是否包含 Origin 字段,如果存在,则认为是跨域请求
 | 
					 | 
				
			||||||
        return request.getHeader("Origin") != null; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -0,0 +1,132 @@ | 
				
			|||||||
 | 
					package cn.soul2.jyjc.admin.utils; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.apache.tomcat.util.codec.binary.Base64; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.crypto.Cipher; | 
				
			||||||
 | 
					import javax.crypto.KeyGenerator; | 
				
			||||||
 | 
					import javax.crypto.spec.SecretKeySpec; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * @author Soul2 | 
				
			||||||
 | 
					 * @date 2024-04-08 15:00 | 
				
			||||||
 | 
					 * <p>照抄自 <a href="https://blog.csdn.net/shaoduo/article/details/122322578">Shao duo</a></p> | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class EncryptUtils { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final String KEY = "620b8d3c3be1e725"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //参数分别代表 算法名称/加密模式/数据填充方式
 | 
				
			||||||
 | 
					    private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 加密 | 
				
			||||||
 | 
					     * | 
				
			||||||
 | 
					     * @param content    加密的字符串 | 
				
			||||||
 | 
					     * @param encryptKey key值 | 
				
			||||||
 | 
					     * @return {@link String} | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public static String encrypt(String content, String encryptKey) throws Exception { | 
				
			||||||
 | 
					        KeyGenerator kgen = KeyGenerator.getInstance("AES"); | 
				
			||||||
 | 
					        kgen.init(128); | 
				
			||||||
 | 
					        Cipher cipher = Cipher.getInstance(ALGORITHMSTR); | 
				
			||||||
 | 
					        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES")); | 
				
			||||||
 | 
					        byte[] b = cipher.doFinal(content.getBytes("utf-8")); | 
				
			||||||
 | 
					        // 采用base64算法进行转码,避免出现中文乱码
 | 
				
			||||||
 | 
					        return Base64.encodeBase64String(b); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 解密 | 
				
			||||||
 | 
					     * | 
				
			||||||
 | 
					     * @param encryptStr 解密的字符串 | 
				
			||||||
 | 
					     * @param decryptKey 解密的key值 | 
				
			||||||
 | 
					     * @return {@link String} | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public static String decrypt(String encryptStr, String decryptKey) throws Exception { | 
				
			||||||
 | 
					        KeyGenerator kgen = KeyGenerator.getInstance("AES"); | 
				
			||||||
 | 
					        kgen.init(128); | 
				
			||||||
 | 
					        Cipher cipher = Cipher.getInstance(ALGORITHMSTR); | 
				
			||||||
 | 
					        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes("utf-8"), "AES")); | 
				
			||||||
 | 
					        // 采用base64算法进行转码,避免出现中文乱码
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //byte[] b = hex2Bytes(encryptStr) ;
 | 
				
			||||||
 | 
					        byte[] encryptBytes = Base64.decodeBase64(encryptStr); | 
				
			||||||
 | 
					        byte[] decryptBytes = cipher.doFinal(encryptBytes); | 
				
			||||||
 | 
					        return new String(decryptBytes); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * @param content 加密的字符串 | 
				
			||||||
 | 
					     * @return {@link String} | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public static String encrypt(String content) throws Exception { | 
				
			||||||
 | 
					        return encrypt(content, KEY); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * @param encryptStr 解密的字符串 | 
				
			||||||
 | 
					     * @return {@link String} | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public static String decrypt(String encryptStr) throws Exception { | 
				
			||||||
 | 
					        return decrypt(encryptStr, KEY); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*    public static void main(String[] args) throws Exception { | 
				
			||||||
 | 
					        Map map=new HashMap<String,String>(); | 
				
			||||||
 | 
					        map.put("key","value"); | 
				
			||||||
 | 
					        map.put("中文","汉字"); | 
				
			||||||
 | 
					        String content = JSONObject.toJSONString(map); | 
				
			||||||
 | 
					        System.out.println("加密前:" + content); | 
				
			||||||
 | 
					        String encrypt = encrypt(content, KEY); | 
				
			||||||
 | 
					        System.out.println("加密后:" + encrypt); | 
				
			||||||
 | 
					        String decrypt = decrypt(encrypt, KEY); | 
				
			||||||
 | 
					        System.out.println("解密后:" + decrypt); | 
				
			||||||
 | 
					    }*/ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * byte数组 转换成 16进制小写字符串 | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public static String bytes2Hex(byte[] bytes) { | 
				
			||||||
 | 
					        if (bytes == null || bytes.length == 0) { | 
				
			||||||
 | 
					            return null; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        StringBuilder hex = new StringBuilder(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (byte b : bytes) { | 
				
			||||||
 | 
					            hex.append(HEXES[(b >> 4) & 0x0F]); | 
				
			||||||
 | 
					            hex.append(HEXES[b & 0x0F]); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return hex.toString(); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** | 
				
			||||||
 | 
					     * 16进制字符串 转换为对应的 byte数组 | 
				
			||||||
 | 
					     */ | 
				
			||||||
 | 
					    public static byte[] hex2Bytes(String hex) { | 
				
			||||||
 | 
					        if (hex == null || hex.length() == 0) { | 
				
			||||||
 | 
					            return null; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        char[] hexChars = hex.toCharArray(); | 
				
			||||||
 | 
					        // 如果 hex 中的字符不是偶数个, 则忽略最后一个
 | 
				
			||||||
 | 
					        byte[] bytes = new byte[hexChars.length / 2]; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (int i = 0; i < bytes.length; i++) { | 
				
			||||||
 | 
					            bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return bytes; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final char[] HEXES = { | 
				
			||||||
 | 
					            '0', '1', '2', '3', | 
				
			||||||
 | 
					            '4', '5', '6', '7', | 
				
			||||||
 | 
					            '8', '9', 'a', 'b', | 
				
			||||||
 | 
					            'c', 'd', 'e', 'f' | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,127 @@ | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?> | 
				
			||||||
 | 
					<configuration scan="true" scanPeriod="10 seconds"> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!--<include resource="org/springframework/boot/logging/logback/base.xml" />--> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <contextName>logback</contextName> | 
				
			||||||
 | 
					    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 --> | 
				
			||||||
 | 
					    <!--    <property name="log.path" value=".logs/"/>--> | 
				
			||||||
 | 
					    <springProperty scope="context" name="log.path" source="logging.path" defaultValue="./logs/"/> | 
				
			||||||
 | 
					    <property name="log.pattern" | 
				
			||||||
 | 
					              value="%cyan(%d{HH:mm:ss}) %green(%-5level) %blue(%logger{50}) - %boldMagenta(%msg) \t\t ---- %yellow([%thread] %d{yyyy-MM-dd HH:mm:ss.SSS}) %n" | 
				
			||||||
 | 
					    /> | 
				
			||||||
 | 
					    <property name="debug.path" value="${log.path}/%d{yyyyMM,aux}/%d{dd,aux}/debug-%d{yyyyMMdd}.%i.log.gz"/> | 
				
			||||||
 | 
					    <property name="info.path" value="${log.path}/%d{yyyyMM,aux}/%d{dd,aux}/info-%d{yyyyMMdd}.%i.log.gz"/> | 
				
			||||||
 | 
					    <property name="error.path" value="${log.path}/%d{yyyyMM,aux}/%d{dd,aux}/error-%d{yyyyMMdd}.%i.log.gz"/> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!--输出到控制台--> | 
				
			||||||
 | 
					    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> | 
				
			||||||
 | 
					        <!-- 控制台输出的日志级别是大于或等于此级别的日志信息 --> | 
				
			||||||
 | 
					        <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> | 
				
			||||||
 | 
					            <level>DEBUG</level> | 
				
			||||||
 | 
					        </filter> | 
				
			||||||
 | 
					        <!--日志文件输出格式与字符集--> | 
				
			||||||
 | 
					        <encoder> | 
				
			||||||
 | 
					            <Pattern>${log.pattern}</Pattern> | 
				
			||||||
 | 
					            <charset>UTF-8</charset> | 
				
			||||||
 | 
					        </encoder> | 
				
			||||||
 | 
					    </appender> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!--输出到文件--> | 
				
			||||||
 | 
					    <!-- 时间滚动输出 level为 DEBUG 日志 --> | 
				
			||||||
 | 
					    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | 
				
			||||||
 | 
					        <!-- 正在记录的日志文件的路径及文件名 --> | 
				
			||||||
 | 
					        <file>${log.path}/debug.log</file> | 
				
			||||||
 | 
					        <!--日志文件输出格式与字符集--> | 
				
			||||||
 | 
					        <encoder> | 
				
			||||||
 | 
					            <pattern>${log.pattern}</pattern> | 
				
			||||||
 | 
					            <charset>UTF-8</charset> | 
				
			||||||
 | 
					        </encoder> | 
				
			||||||
 | 
					        <!-- 日志记录器的滚动策略,按日期,按大小记录 --> | 
				
			||||||
 | 
					        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | 
				
			||||||
 | 
					            <!-- 日志归档 --> | 
				
			||||||
 | 
					            <fileNamePattern>${debug.path}</fileNamePattern> | 
				
			||||||
 | 
					            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> | 
				
			||||||
 | 
					                <maxFileSize>10MB</maxFileSize> | 
				
			||||||
 | 
					            </timeBasedFileNamingAndTriggeringPolicy> | 
				
			||||||
 | 
					            <!--日志文件保留天数--> | 
				
			||||||
 | 
					            <maxHistory>7</maxHistory> | 
				
			||||||
 | 
					        </rollingPolicy> | 
				
			||||||
 | 
					        <!-- 此日志文件记录debug级别以上的 --> | 
				
			||||||
 | 
					        <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> | 
				
			||||||
 | 
					            <level>DEBUG</level> | 
				
			||||||
 | 
					        </filter> | 
				
			||||||
 | 
					    </appender> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- 时间滚动输出 level为 INFO 日志 --> | 
				
			||||||
 | 
					    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | 
				
			||||||
 | 
					        <!-- 正在记录的日志文件的路径及文件名 --> | 
				
			||||||
 | 
					        <file>${log.path}/info.log</file> | 
				
			||||||
 | 
					        <!--日志文件输出格式--> | 
				
			||||||
 | 
					        <encoder> | 
				
			||||||
 | 
					            <pattern>${log.pattern}</pattern> | 
				
			||||||
 | 
					            <charset>UTF-8</charset> | 
				
			||||||
 | 
					        </encoder> | 
				
			||||||
 | 
					        <!-- 日志记录器的滚动策略,按日期,按大小记录 --> | 
				
			||||||
 | 
					        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | 
				
			||||||
 | 
					            <!-- 每天日志归档路径以及格式 --> | 
				
			||||||
 | 
					            <fileNamePattern>${info.path}</fileNamePattern> | 
				
			||||||
 | 
					            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> | 
				
			||||||
 | 
					                <maxFileSize>100MB</maxFileSize> | 
				
			||||||
 | 
					            </timeBasedFileNamingAndTriggeringPolicy> | 
				
			||||||
 | 
					            <!--日志文件保留天数--> | 
				
			||||||
 | 
					            <maxHistory>60</maxHistory> | 
				
			||||||
 | 
					        </rollingPolicy> | 
				
			||||||
 | 
					        <!-- 此日志文件记录info级别以上的 --> | 
				
			||||||
 | 
					        <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> | 
				
			||||||
 | 
					            <level>INFO</level> | 
				
			||||||
 | 
					        </filter> | 
				
			||||||
 | 
					    </appender> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- 时间滚动输出 level为 ERROR 日志 --> | 
				
			||||||
 | 
					    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | 
				
			||||||
 | 
					        <!-- 正在记录的日志文件的路径及文件名 --> | 
				
			||||||
 | 
					        <file>${log.path}/error.log</file> | 
				
			||||||
 | 
					        <!--日志文件输出格式--> | 
				
			||||||
 | 
					        <encoder> | 
				
			||||||
 | 
					            <pattern>${log.pattern}</pattern> | 
				
			||||||
 | 
					            <charset>UTF-8</charset> <!-- 此处设置字符集 --> | 
				
			||||||
 | 
					        </encoder> | 
				
			||||||
 | 
					        <!-- 日志记录器的滚动策略,按日期,按大小记录 --> | 
				
			||||||
 | 
					        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | 
				
			||||||
 | 
					            <fileNamePattern>${error.path}</fileNamePattern> | 
				
			||||||
 | 
					            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> | 
				
			||||||
 | 
					                <maxFileSize>10MB</maxFileSize> | 
				
			||||||
 | 
					            </timeBasedFileNamingAndTriggeringPolicy> | 
				
			||||||
 | 
					            <!--日志文件保留天数--> | 
				
			||||||
 | 
					            <maxHistory>60</maxHistory> | 
				
			||||||
 | 
					        </rollingPolicy> | 
				
			||||||
 | 
					        <!-- 此日志文件记录error级别以上的 --> | 
				
			||||||
 | 
					        <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> | 
				
			||||||
 | 
					            <level>ERROR</level> | 
				
			||||||
 | 
					        </filter> | 
				
			||||||
 | 
					    </appender> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!--开发环境:打印控制台--> | 
				
			||||||
 | 
					    <springProfile name="local,dev,test"> | 
				
			||||||
 | 
					        <logger level="DEBUG" additivity="false" name="cn.soul2"> | 
				
			||||||
 | 
					            <appender-ref ref="CONSOLE"/> | 
				
			||||||
 | 
					            <appender-ref ref="DEBUG_FILE"/> | 
				
			||||||
 | 
					            <appender-ref ref="INFO_FILE"/> | 
				
			||||||
 | 
					            <appender-ref ref="ERROR_FILE"/> | 
				
			||||||
 | 
					        </logger> | 
				
			||||||
 | 
					        <root level="INFO"> | 
				
			||||||
 | 
					            <appender-ref ref="CONSOLE"/> | 
				
			||||||
 | 
					            <appender-ref ref="INFO_FILE"/> | 
				
			||||||
 | 
					            <appender-ref ref="ERROR_FILE"/> | 
				
			||||||
 | 
					        </root> | 
				
			||||||
 | 
					    </springProfile> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!--生产环境:输出到文件--> | 
				
			||||||
 | 
					    <springProfile name="pre,prod,prod-yun"> | 
				
			||||||
 | 
					        <root level="INFO"> | 
				
			||||||
 | 
					            <appender-ref ref="INFO_FILE"/> | 
				
			||||||
 | 
					            <appender-ref ref="ERROR_FILE"/> | 
				
			||||||
 | 
					        </root> | 
				
			||||||
 | 
					    </springProfile> | 
				
			||||||
 | 
					</configuration> | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue