more enhancement

This commit is contained in:
rongqian.xu 2021-10-11 18:40:15 +08:00
parent f47bea66ff
commit 1ca0840994
45 changed files with 637 additions and 480 deletions

4
.gitignore vendored

@ -42,3 +42,7 @@ nbdist/
!*/build/*.java
!*/build/*.html
!*/build/*.xml
ruoyi-ui/node/
ruoyi-ui/node_modules/
ruoyi-admin/src/main/resources/public/

@ -42,6 +42,14 @@
演示地址http://vue.ruoyi.vip
文档地址http://doc.ruoyi.vip
## 快速开始
1. 准备好mysql和redis
2. mysql导入sql目录下的所有sql文件
3. 修改ruoyi-admin/src/main/resources/application.yml的redis连接信息
4. 修改ruoyi-admin/src/main/resources/application-druid.yml的mysql连接信息
5. 执行maven命令构建 ```mvn clean package```
6. 执行命令启动 ```java -jar ruoyi-admin/target/ruoyi-admin.jar```
## 演示图
<table>

@ -205,6 +205,14 @@
<version>${ruoyi.version}</version>
</dependency>
<!-- 前端代码 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-ui</artifactId>
<version>${ruoyi.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -215,6 +223,7 @@
<module>ruoyi-quartz</module>
<module>ruoyi-generator</module>
<module>ruoyi-common</module>
<module>ruoyi-ui</module>
</modules>
<packaging>pom</packaging>

@ -61,6 +61,12 @@
<artifactId>ruoyi-generator</artifactId>
</dependency>
<!-- 前端代码 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-ui</artifactId>
</dependency>
</dependencies>
<build>
@ -88,7 +94,47 @@
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<filesets>
<fileset>
<directory>src/main/resources/public</directory>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>copy Vue.js frontend content</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>src/main/resources/public</outputDirectory>
<overwrite>true</overwrite>
<resources>
<resource>
<directory>${project.parent.basedir}/ruoyi-ui/dist</directory>
<includes>
<include>static/</include>
<include>html/</include>
<include>index.html</include>
<include>favicon.ico</include>
<include>robots.txt</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>

@ -10,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.Producer;
import com.ruoyi.common.constant.Constants;
@ -25,6 +26,7 @@ import com.ruoyi.system.service.ISysConfigService;
* @author ruoyi
*/
@RestController
@RequestMapping("/api")
public class CaptchaController
{
@Resource(name = "captchaProducer")

@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.config.RuoYiConfig;
@ -24,6 +25,7 @@ import com.ruoyi.framework.config.ServerConfig;
* @author ruoyi
*/
@RestController
@RequestMapping("/api")
public class CommonController
{
private static final Logger log = LoggerFactory.getLogger(CommonController.class);

@ -21,7 +21,7 @@ import com.ruoyi.common.utils.StringUtils;
* @author ruoyi
*/
@RestController
@RequestMapping("/monitor/cache")
@RequestMapping("/api/monitor/cache")
public class CacheController
{
@Autowired

@ -13,7 +13,7 @@ import com.ruoyi.framework.web.domain.Server;
* @author ruoyi
*/
@RestController
@RequestMapping("/monitor/server")
@RequestMapping("/api/monitor/server")
public class ServerController
{
@PreAuthorize("@ss.hasPermi('monitor:server:list')")

@ -23,7 +23,7 @@ import com.ruoyi.system.service.ISysLogininforService;
* @author ruoyi
*/
@RestController
@RequestMapping("/monitor/logininfor")
@RequestMapping("/api/monitor/logininfor")
public class SysLogininforController extends BaseController
{
@Autowired

@ -23,7 +23,7 @@ import com.ruoyi.system.service.ISysOperLogService;
* @author ruoyi
*/
@RestController
@RequestMapping("/monitor/operlog")
@RequestMapping("/api/monitor/operlog")
public class SysOperlogController extends BaseController
{
@Autowired

@ -29,7 +29,7 @@ import com.ruoyi.system.service.ISysUserOnlineService;
* @author ruoyi
*/
@RestController
@RequestMapping("/monitor/online")
@RequestMapping("/api/monitor/online")
public class SysUserOnlineController extends BaseController
{
@Autowired

@ -29,7 +29,7 @@ import com.ruoyi.system.service.ISysConfigService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/config")
@RequestMapping("/api/system/config")
public class SysConfigController extends BaseController
{
@Autowired

@ -29,7 +29,7 @@ import com.ruoyi.system.service.ISysDeptService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/dept")
@RequestMapping("/api/system/dept")
public class SysDeptController extends BaseController
{
@Autowired

@ -30,7 +30,7 @@ import com.ruoyi.system.service.ISysDictTypeService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/dict/data")
@RequestMapping("/api/system/dict/data")
public class SysDictDataController extends BaseController
{
@Autowired

@ -28,7 +28,7 @@ import com.ruoyi.system.service.ISysDictTypeService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/dict/type")
@RequestMapping("/api/system/dict/type")
public class SysDictTypeController extends BaseController
{
@Autowired

@ -12,6 +12,7 @@ import com.ruoyi.common.utils.StringUtils;
* @author ruoyi
*/
@RestController
@RequestMapping("/api")
public class SysIndexController
{
/** 系统基础配置 */
@ -21,7 +22,7 @@ public class SysIndexController
/**
* 访问首页提示语
*/
@RequestMapping("/")
@RequestMapping("/info")
public String index()
{
return StringUtils.format("欢迎使用{}后台管理框架当前版本v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());

@ -3,10 +3,7 @@ package com.ruoyi.web.controller.system;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
@ -23,6 +20,7 @@ import com.ruoyi.system.service.ISysMenuService;
* @author ruoyi
*/
@RestController
@RequestMapping("/api")
public class SysLoginController
{
@Autowired

@ -27,7 +27,7 @@ import com.ruoyi.system.service.ISysMenuService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/menu")
@RequestMapping("/api/system/menu")
public class SysMenuController extends BaseController
{
@Autowired

@ -26,7 +26,7 @@ import com.ruoyi.system.service.ISysNoticeService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/notice")
@RequestMapping("/api/system/notice")
public class SysNoticeController extends BaseController
{
@Autowired

@ -28,7 +28,7 @@ import com.ruoyi.system.service.ISysPostService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/post")
@RequestMapping("/api/system/post")
public class SysPostController extends BaseController
{
@Autowired

@ -30,7 +30,7 @@ import com.ruoyi.system.service.ISysUserService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/user/profile")
@RequestMapping("/api/system/user/profile")
public class SysProfileController extends BaseController
{
@Autowired

@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
@ -17,6 +18,7 @@ import com.ruoyi.system.service.ISysConfigService;
* @author ruoyi
*/
@RestController
@RequestMapping("/api")
public class SysRegisterController extends BaseController
{
@Autowired

@ -35,7 +35,7 @@ import com.ruoyi.system.service.ISysUserService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/role")
@RequestMapping("/api/system/role")
public class SysRoleController extends BaseController
{
@Autowired

@ -36,7 +36,7 @@ import com.ruoyi.system.service.ISysUserService;
* @author ruoyi
*/
@RestController
@RequestMapping("/system/user")
@RequestMapping("/api/system/user")
public class SysUserController extends BaseController
{
@Autowired

@ -12,7 +12,7 @@ import com.ruoyi.common.core.controller.BaseController;
* @author ruoyi
*/
@Controller
@RequestMapping("/tool/swagger")
@RequestMapping("/api/tool/swagger")
public class SwaggerController extends BaseController
{
@PreAuthorize("@ss.hasPermi('tool:swagger:view')")

@ -29,7 +29,7 @@ import io.swagger.annotations.ApiOperation;
*/
@Api("用户信息管理")
@RestController
@RequestMapping("/test/user")
@RequestMapping("/api/test/user")
public class TestController extends BaseController
{
private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();

@ -56,10 +56,10 @@ public class SwaggerConfig
// 设置哪些接口暴露给Swagger展示
.select()
// 扫描所有有注解的api用这种方式更灵活
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
// 扫描指定包中的swagger注解
// .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
// 扫描所有 .apis(RequestHandlerSelectors.any())
.apis(RequestHandlerSelectors.any()) //扫描所有
.paths(PathSelectors.any())
.build()
/* 设置安全模式swagger可以设置访问token */

@ -6,9 +6,9 @@ spring:
druid:
# 主库数据源
master:
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://localhost:3306/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: password
password: root
# 从库数据源
slave:
# 从数据源开关/默认关闭
@ -41,7 +41,7 @@ spring:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
url-pattern: /api/druid/*
# 控制台管理用户名和密码
login-username: ruoyi
login-password: 123456

@ -33,8 +33,8 @@ server:
# 日志配置
logging:
level:
com.ruoyi: debug
org.springframework: warn
com.ruoyi: info
org.springframework: info
# Spring配置
spring:
@ -59,7 +59,7 @@ spring:
# redis 配置
redis:
# 地址
host: localhost
host: 192.168.56.101
# 端口默认为6379
port: 6379
# 数据库索引
@ -108,13 +108,13 @@ swagger:
# 是否开启swagger
enabled: true
# 请求前缀
pathMapping: /dev-api
pathMapping: /
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice
excludes: /api/system/notice
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
urlPatterns: /api/system/*,/api/monitor/*,/api/tool/*

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/home/ruoyi/logs" />
<property name="log.path" value="${log.dir}" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
@ -74,7 +74,7 @@
<!-- 系统模块日志级别控制 -->
<logger name="com.ruoyi" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<logger name="org.springframework" level="info" />
<root level="info">
<appender-ref ref="console" />

@ -1,152 +1,149 @@
package com.ruoyi.common.utils;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.text.Convert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.ruoyi.common.core.text.Convert;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 客户端工具类
*
*
* @author ruoyi
*/
public class ServletUtils
{
public class ServletUtils {
/**
* 获取String参数
*/
public static String getParameter(String name)
{
public static String getParameter(String name) {
return getRequest().getParameter(name);
}
/**
* 获取String参数
*/
public static String getParameter(String name, String defaultValue)
{
public static String getParameter(String name, String defaultValue) {
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name)
{
public static Integer getParameterToInt(String name) {
return Convert.toInt(getRequest().getParameter(name));
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name, Integer defaultValue)
{
public static Integer getParameterToInt(String name, Integer defaultValue) {
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name)
{
public static Boolean getParameterToBool(String name) {
return Convert.toBool(getRequest().getParameter(name));
}
/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name, Boolean defaultValue)
{
public static Boolean getParameterToBool(String name, Boolean defaultValue) {
return Convert.toBool(getRequest().getParameter(name), defaultValue);
}
/**
* 获取request
*/
public static HttpServletRequest getRequest()
{
public static HttpServletRequest getRequest() {
return getRequestAttributes().getRequest();
}
/**
* 获取response
*/
public static HttpServletResponse getResponse()
{
public static HttpServletResponse getResponse() {
return getRequestAttributes().getResponse();
}
/**
* 获取session
*/
public static HttpSession getSession()
{
public static HttpSession getSession() {
return getRequest().getSession();
}
public static ServletRequestAttributes getRequestAttributes()
{
public static ServletRequestAttributes getRequestAttributes() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
}
/**
* 将字符串渲染到客户端
*
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @param string 待渲染的字符串
* @return null
*/
public static String renderString(HttpServletResponse response, String string)
{
try
{
response.setStatus(200);
public static void renderString(HttpServletResponse response, String string) {
renderString(response, HttpStatus.SUCCESS, string);
}
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param status 状态码
* @param string 待渲染的字符串
* @return null
*/
public static void renderString(HttpServletResponse response, int status, String string) {
try {
response.setStatus(status);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
} catch (IOException e) {
throw new RuntimeException(e);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
/**
* 是否是Ajax异步请求
*
*
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request)
{
public static boolean isAjaxRequest(HttpServletRequest request) {
String accept = request.getHeader("accept");
if (accept != null && accept.indexOf("application/json") != -1)
{
if (accept != null && accept.indexOf("application/json") != -1) {
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1)
{
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
return true;
}
String uri = request.getRequestURI();
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
{
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {
return true;
}
String ajax = request.getParameter("__ajax");
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml"))
{
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) {
return true;
}
return false;
}
public static boolean isApiRequest(HttpServletRequest request){
return request.getRequestURI().startsWith("/api");
}
}

@ -1,45 +1,63 @@
package com.ruoyi.framework.config;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
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.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
import org.springframework.web.servlet.resource.PathResourceResolver;
import java.io.IOException;
/**
* 通用配置
*
*
* @author ruoyi
*/
@Configuration
public class ResourcesConfig implements WebMvcConfigurer
{
public class ResourcesConfig implements WebMvcConfigurer {
@Autowired
private RepeatSubmitInterceptor repeatSubmitInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/** 本地文件上传路径 */
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
/** swagger配置 */
registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
registry.addResourceHandler("/**/*")
.addResourceLocations("classpath:/public/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
@Override
protected Resource getResource(String resourcePath,
Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/public/index.html");
}
});
}
/**
* 自定义拦截规则
*/
@Override
public void addInterceptors(InterceptorRegistry registry)
{
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
}
@ -47,8 +65,7 @@ public class ResourcesConfig implements WebMvcConfigurer
* 跨域配置
*/
@Bean
public CorsFilter corsFilter()
{
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);

@ -1,6 +1,10 @@
package com.ruoyi.framework.config;
import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
@ -14,24 +18,20 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
/**
* spring security配置
*
*
* @author ruoyi
*/
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 自定义用户认证逻辑
*/
@Autowired
private UserDetailsService userDetailsService;
/**
* 认证失败处理类
*/
@ -49,13 +49,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
*/
@Autowired
private JwtAuthenticationTokenFilter authenticationTokenFilter;
/**
* 跨域过滤器
*/
@Autowired
private CorsFilter corsFilter;
/**
* 解决 无法直接注入 AuthenticationManager
*
@ -64,8 +64,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@ -85,8 +84,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
* authenticated | 用户登录后可访问
*/
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
{
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// CSRF禁用因为不使用session
.csrf().disable()
@ -97,7 +95,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 过滤请求
.authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/register", "/captchaImage").anonymous()
.antMatchers("/login", "/api/login", "/api/register", "/api/captchaImage", "/error").permitAll()
.antMatchers(
HttpMethod.GET,
"/",
@ -105,18 +103,22 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/**/*.ico",
"/static/**",
"/html/**",
"/profile/**"
).permitAll()
.antMatchers("/swagger-ui.html").anonymous()
.antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous()
.antMatchers("/druid/**").anonymous()
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll()
.antMatchers( "/api/druid/**").permitAll()
.antMatchers( "/public/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
.and()
.headers().frameOptions().disable();
httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
httpSecurity.logout().logoutUrl("/api/logout").logoutSuccessHandler(logoutSuccessHandler);
// 添加JWT filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 添加CORS filter
@ -128,8 +130,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
* 强散列哈希加密实现
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder()
{
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@ -137,8 +138,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
* 身份认证接口
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}

@ -1,34 +1,38 @@
package com.ruoyi.framework.security.handle;
import java.io.IOException;
import java.io.Serializable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.security.core.AuthenticationException;
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.Serializable;
import java.net.URLEncoder;
/**
* 认证失败处理类 返回未授权
*
*
* @author ruoyi
*/
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable
{
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable {
private static final long serialVersionUID = -8970718410437077606L;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
throws IOException
{
int code = HttpStatus.UNAUTHORIZED;
throws IOException {
String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
int code = HttpStatus.UNAUTHORIZED;
if (ServletUtils.isAjaxRequest(request) || ServletUtils.isApiRequest(request)) {
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
} else {
response.sendRedirect("/login?redirect=" + URLEncoder.encode(request.getRequestURI(), "utf8"));
}
}
}

@ -1,12 +1,5 @@
package com.ruoyi.framework.web.service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
@ -19,6 +12,16 @@ import eu.bitwalker.useragentutils.UserAgent;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* token验证处理
@ -26,8 +29,8 @@ import io.jsonwebtoken.SignatureAlgorithm;
* @author ruoyi
*/
@Component
public class TokenService
{
public class TokenService {
public static final String COOKIE_TOKEN_NAME = "Admin-Token";
// 令牌自定义标识
@Value("${token.header}")
private String header;
@ -54,23 +57,18 @@ public class TokenService
*
* @return 用户信息
*/
public LoginUser getLoginUser(HttpServletRequest request)
{
public LoginUser getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token))
{
try
{
if (StringUtils.isNotEmpty(token)) {
try {
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
return user;
}
catch (Exception e)
{
} catch (Exception e) {
}
}
return null;
@ -79,10 +77,8 @@ public class TokenService
/**
* 设置用户身份信息
*/
public void setLoginUser(LoginUser loginUser)
{
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
{
public void setLoginUser(LoginUser loginUser) {
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) {
refreshToken(loginUser);
}
}
@ -90,10 +86,8 @@ public class TokenService
/**
* 删除用户身份信息
*/
public void delLoginUser(String token)
{
if (StringUtils.isNotEmpty(token))
{
public void delLoginUser(String token) {
if (StringUtils.isNotEmpty(token)) {
String userKey = getTokenKey(token);
redisCache.deleteObject(userKey);
}
@ -105,8 +99,7 @@ public class TokenService
* @param loginUser 用户信息
* @return 令牌
*/
public String createToken(LoginUser loginUser)
{
public String createToken(LoginUser loginUser) {
String token = IdUtils.fastUUID();
loginUser.setToken(token);
setUserAgent(loginUser);
@ -123,12 +116,10 @@ public class TokenService
* @param loginUser
* @return 令牌
*/
public void verifyToken(LoginUser loginUser)
{
public void verifyToken(LoginUser loginUser) {
long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
{
if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
refreshToken(loginUser);
}
}
@ -138,8 +129,7 @@ public class TokenService
*
* @param loginUser 登录信息
*/
public void refreshToken(LoginUser loginUser)
{
public void refreshToken(LoginUser loginUser) {
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存
@ -152,8 +142,7 @@ public class TokenService
*
* @param loginUser 登录信息
*/
public void setUserAgent(LoginUser loginUser)
{
public void setUserAgent(LoginUser loginUser) {
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
loginUser.setIpaddr(ip);
@ -168,8 +157,7 @@ public class TokenService
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map<String, Object> claims)
{
private String createToken(Map<String, Object> claims) {
String token = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
@ -182,8 +170,7 @@ public class TokenService
* @param token 令牌
* @return 数据声明
*/
private Claims parseToken(String token)
{
private Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
@ -196,8 +183,7 @@ public class TokenService
* @param token 令牌
* @return 用户名
*/
public String getUsernameFromToken(String token)
{
public String getUsernameFromToken(String token) {
Claims claims = parseToken(token);
return claims.getSubject();
}
@ -208,18 +194,35 @@ public class TokenService
* @param request
* @return token
*/
private String getToken(HttpServletRequest request)
{
private String getToken(HttpServletRequest request) {
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
{
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) {
token = token.replace(Constants.TOKEN_PREFIX, "");
}
if (StringUtils.isEmpty(token)) {
Optional<String> tokenOpt = getCookie(request, COOKIE_TOKEN_NAME);
if (tokenOpt.isPresent()) {
token = tokenOpt.get();
}
}
return token;
}
private String getTokenKey(String uuid)
{
private Optional<String> getCookie(HttpServletRequest request, String name) {
if (request.getCookies() == null) {
return Optional.empty();
}
for (Cookie cookie : request.getCookies()) {
if (StringUtils.equals(name, cookie.getName())) {
return Optional.of(cookie.getValue());
}
}
return Optional.empty();
}
private String getTokenKey(String uuid) {
return Constants.LOGIN_TOKEN_KEY + uuid;
}
}

@ -34,7 +34,7 @@ import com.ruoyi.generator.service.IGenTableService;
* @author ruoyi
*/
@RestController
@RequestMapping("/tool/gen")
@RequestMapping("/api/tool/gen")
public class GenController extends BaseController
{
@Autowired

@ -31,7 +31,7 @@ import com.ruoyi.quartz.util.CronUtils;
* @author ruoyi
*/
@RestController
@RequestMapping("/monitor/job")
@RequestMapping("/api/monitor/job")
public class SysJobController extends BaseController
{
@Autowired

@ -23,7 +23,7 @@ import com.ruoyi.quartz.service.ISysJobLogService;
* @author ruoyi
*/
@RestController
@RequestMapping("/monitor/jobLog")
@RequestMapping("/api/monitor/jobLog")
public class SysJobLogController extends BaseController
{
@Autowired

@ -1,11 +1,11 @@
# 页面标题
VUE_APP_TITLE = 若依管理系统
# 开发环境配置
ENV = 'development'
# 若依管理系统/开发环境
VUE_APP_BASE_API = '/dev-api'
# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true
# 页面标题
VUE_APP_TITLE = 若依管理系统
# 开发环境配置
ENV = 'development'
# 若依管理系统/开发环境
VUE_APP_BASE_API = '/api'
# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true

@ -1,8 +1,8 @@
# 页面标题
VUE_APP_TITLE = 若依管理系统
# 生产环境配置
ENV = 'production'
# 若依管理系统/生产环境
VUE_APP_BASE_API = '/prod-api'
# 页面标题
VUE_APP_TITLE = 若依管理系统
# 生产环境配置
ENV = 'production'
# 若依管理系统/生产环境
VUE_APP_BASE_API = '/api'

@ -1,88 +1,88 @@
{
"name": "ruoyi",
"version": "3.7.0",
"description": "若依管理系统",
"author": "若依",
"license": "MIT",
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"keywords": [
"vue",
"admin",
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
],
"repository": {
"type": "git",
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
},
"dependencies": {
"@riophae/vue-treeselect": "0.4.0",
"axios": "0.21.0",
"clipboard": "2.0.6",
"core-js": "3.8.1",
"echarts": "4.9.0",
"element-ui": "2.15.6",
"file-saver": "2.0.5",
"fuse.js": "6.4.3",
"highlight.js": "9.18.5",
"js-beautify": "1.13.0",
"js-cookie": "2.2.1",
"jsencrypt": "3.0.0-rc.1",
"nprogress": "0.2.0",
"quill": "1.3.7",
"screenfull": "5.0.2",
"sortablejs": "1.10.2",
"vue": "2.6.12",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.5",
"vue-meta": "^2.4.0",
"vue-router": "3.4.9",
"vuedraggable": "2.24.3",
"vuex": "3.6.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-service": "4.4.6",
"babel-eslint": "10.1.0",
"chalk": "4.1.0",
"connect": "3.6.6",
"eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0",
"lint-staged": "10.5.3",
"runjs": "4.4.2",
"sass": "1.32.13",
"sass-loader": "10.1.1",
"script-ext-html-webpack-plugin": "2.1.5",
"svg-sprite-loader": "5.1.1",
"vue-template-compiler": "2.6.12"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}
{
"name": "ruoyi",
"version": "3.7.0",
"description": "若依管理系统",
"author": "若依",
"license": "MIT",
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"keywords": [
"vue",
"admin",
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
],
"repository": {
"type": "git",
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
},
"dependencies": {
"@riophae/vue-treeselect": "0.4.0",
"axios": "0.21.0",
"clipboard": "2.0.6",
"core-js": "3.8.1",
"echarts": "4.9.0",
"element-ui": "2.15.6",
"file-saver": "2.0.5",
"fuse.js": "6.4.3",
"highlight.js": "9.18.5",
"js-beautify": "1.13.0",
"js-cookie": "2.2.1",
"jsencrypt": "3.0.0-rc.1",
"nprogress": "0.2.0",
"quill": "1.3.7",
"screenfull": "5.0.2",
"sortablejs": "1.10.2",
"vue": "2.6.12",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.5",
"vue-meta": "^2.4.0",
"vue-router": "3.4.9",
"vuedraggable": "2.24.3",
"vuex": "3.6.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-service": "4.4.6",
"babel-eslint": "10.1.0",
"chalk": "4.1.0",
"connect": "3.6.6",
"eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0",
"lint-staged": "10.5.3",
"runjs": "4.4.2",
"sass": "1.32.13",
"sass-loader": "10.1.1",
"script-ext-html-webpack-plugin": "2.1.5",
"svg-sprite-loader": "5.1.1",
"vue-template-compiler": "2.6.12"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}

64
ruoyi-ui/pom.xml Normal file

@ -0,0 +1,64 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.7.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-ui</artifactId>
<description>
UI前端项目
</description>
<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<!-- Use the latest released version:
https://repo1.maven.org/maven2/com/github/eirslett/frontend-maven-plugin/ -->
<version>1.9.1</version>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<configuration>
<nodeVersion>v9.11.1</nodeVersion>
</configuration>
</execution>
<!-- Install all project dependencies -->
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<!-- optional: default phase is "generate-resources" -->
<phase>generate-resources</phase>
<!-- Optional configuration which provides for running any npm command -->
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<!-- Build and minify static files -->
<execution>
<id>npm run build</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run build:prod</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -1,53 +1,53 @@
import request from '@/utils/request'
// 登录方法
export function login(username, password, code, uuid) {
const data = {
username,
password,
code,
uuid
}
return request({
url: '/login',
method: 'post',
data: data
})
}
// 注册方法
export function register(data) {
return request({
url: '/register',
headers: {
isToken: false
},
method: 'post',
data: data
})
}
// 获取用户详细信息
export function getInfo() {
return request({
url: '/getInfo',
method: 'get'
})
}
// 退出方法
export function logout() {
return request({
url: '/logout',
method: 'post'
})
}
// 获取验证码
export function getCodeImg() {
return request({
url: '/captchaImage',
method: 'get',
timeout: 20000
})
}
import request from '@/utils/request'
// 登录方法
export function login(username, password, code, uuid) {
const data = {
username,
password,
code,
uuid
}
return request({
url: '/login',
method: 'post',
data: data
})
}
// 注册方法
export function register(data) {
return request({
url: '/register',
headers: {
isToken: false
},
method: 'post',
data: data
})
}
// 获取用户详细信息
export function getInfo() {
return request({
url: '/getInfo',
method: 'get'
})
}
// 退出方法
export function logout() {
return request({
url: '/logout',
method: 'post'
})
}
// 获取验证码
export function getCodeImg() {
return request({
url: '/captchaImage',
method: 'get',
timeout: 20000
})
}

@ -1,15 +1,15 @@
<template>
<i-frame :src="url" />
</template>
<script>
import iFrame from "@/components/iFrame/index";
export default {
name: "Swagger",
components: { iFrame },
data() {
return {
url: process.env.VUE_APP_BASE_API + "/swagger-ui/index.html"
};
},
};
</script>
<template>
<i-frame :src="url" />
</template>
<script>
import iFrame from "@/components/iFrame/index";
export default {
name: "Swagger",
components: { iFrame },
data() {
return {
url: "/swagger-ui/index.html"
};
},
};
</script>

@ -1,117 +1,117 @@
'use strict'
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题
const port = process.env.port || process.env.npm_config_port || 80 // 端口
// vue.config.js 配置说明
//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
// 这里只列一部分,具体配置参考文档
module.exports = {
// 部署生产环境和开发环境下的URL。
// 默认情况下Vue CLI 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
// 在npm run build 或 yarn build 时 生成文件的目录名称要和baseUrl的生产环境路径一致默认dist
outputDir: 'dist',
// 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
assetsDir: 'static',
// 是否开启eslint保存检测有效值ture | false | 'error'
lintOnSave: process.env.NODE_ENV === 'development',
// 如果你不需要生产环境的 source map可以将其设置为 false 以加速生产环境构建。
productionSourceMap: false,
// webpack-dev-server 相关配置
devServer: {
host: '0.0.0.0',
port: port,
open: true,
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://localhost:8080`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
},
disableHostCheck: true
},
configureWebpack: {
name: name,
resolve: {
alias: {
'@': resolve('src')
}
}
},
chainWebpack(config) {
config.plugins.delete('preload') // TODO: need test
config.plugins.delete('prefetch') // TODO: need test
// set svg-sprite-loader
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
config
.when(process.env.NODE_ENV !== 'development',
config => {
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/
}])
.end()
config
.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
config.optimization.runtimeChunk('single'),
{
from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
to: './' //到根目录下
}
}
)
}
}
'use strict'
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题
const port = process.env.port || process.env.npm_config_port || 80 // 端口
// vue.config.js 配置说明
//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
// 这里只列一部分,具体配置参考文档
module.exports = {
// 部署生产环境和开发环境下的URL。
// 默认情况下Vue CLI 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
// 在npm run build 或 yarn build 时 生成文件的目录名称要和baseUrl的生产环境路径一致默认dist
outputDir: 'dist',
// 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
assetsDir: 'static',
// 是否开启eslint保存检测有效值ture | false | 'error'
lintOnSave: process.env.NODE_ENV === 'development',
// 如果你不需要生产环境的 source map可以将其设置为 false 以加速生产环境构建。
productionSourceMap: false,
// webpack-dev-server 相关配置
devServer: {
host: '0.0.0.0',
port: port,
open: true,
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://localhost:8080`,
changeOrigin: true
//pathRewrite: {
// ['^' + process.env.VUE_APP_BASE_API]: ''
// }
}
},
disableHostCheck: true
},
configureWebpack: {
name: name,
resolve: {
alias: {
'@': resolve('src')
}
}
},
chainWebpack(config) {
config.plugins.delete('preload') // TODO: need test
config.plugins.delete('prefetch') // TODO: need test
// set svg-sprite-loader
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
config
.when(process.env.NODE_ENV !== 'development',
config => {
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/
}])
.end()
config
.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
config.optimization.runtimeChunk('single'),
{
from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
to: './' //到根目录下
}
}
)
}
}