常见问题
如何新增系统图标
如果你没有在本项目 Icon中找到需要的图标,可以到 iconfont.cn 上选择并生成自己的业务图标库,再进行使用。或者其它 svg 图标网站,下载 svg 并放到文件夹之中就可以了。
下载完成之后将下载好的 .svg 文件放入 @/icons/svg 文件夹下之后就会自动导入。
使用方式
<svg-icon icon-class="password" /> // icon-class 为 icon 的名字
💡 提示: 菜单图标会自动引入@/icons/svg,放入此文件夹中图标就可以选择了
如何不登录直接访问
方法1:在SecurityConfig.java中设置httpSecurity配置匿名访问
// 使用 permitAll() 方法所有人都能访问,包括带上 token 访问
.antMatchers("/admins/**").permitAll()
// 使用 anonymous() 所有人都能访问,但是带上 token 访问后会报错
.antMatchers("/admins/**").anonymous()
法2:在对应的方法或类上面使用@Anonymous注解。
// 类上定义匿名注解,作用于所有的方法
@Anonymous
@RestController
@RequestMapping("/system/xxxx")
public class SysXxxxController extends BaseController
{
}
// 方法定义匿名注解,作用于单独的方法
@Anonymous
@GetMapping("/list")
public List<SysXxxx> list(SysXxxx xxxx)
{
    return xxxxList;
}
⚠️警告: 匿名访问的方法上面@PreAuthorize权限注解也需要去掉,因为已经使用匿名访问了,权限自然也不需要去验证了。
💡 前端不登录如何直接访问: 如果是前端页面可以在src/permission.js配置whiteList属性白名单即可。
如何更换主题皮肤
默认的主题都是深色主题,如果需要其他主题可以做如下配置。
1、点击顶部最右侧个人中心头像,选择布局设置,选择主题风格设置。(局部设置)
2、在gyj-iot-web\src\settings.js,设置侧边栏主题sideTheme为theme-xxxx。(全局设置)
移除或自定义首页
默认登录是指向首页仪表盘。如果想移除或修改,可以参考以下步骤。
1、打开router/index.js文件,找到首页路由配置并将改为自定义页面:
// {
//   path: '',
//   component: Layout,
//   redirect: 'index',
//   children: [
//     {
//       path: 'index',
//       component: () => import('@/views/index'),
//       name: 'Index',
//       meta: { title: '首页', icon: 'dashboard', affix: true }
//     }
//   ]
// },
{
    path: '',
    component: Layout,
    redirect: '/system/user',
},
2、修改login.vue文件,去掉redirect参数
// this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
this.$router.push({ path: "/" }).catch(()=>{});
3、打开Breadcrumb/index.vue文件,删除或注释首页判断代码
//  // 判断是否为首页
//  if (!this.isDashboard(matched[0])) {
//    matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched)
//  }
4、修改TagsView/index.vue文件,对最后一个标签限制删除
closeSelectedTag(view) {
  if (this.visitedViews.length == 1) {
	  this.$modal.msgWarning("当前为最后一个页签,不允许删除。");
	  return;
  }
  ....
},
如何实现动态菜单
有时候经常会需要将系统的某个菜单打开多个相同的明细页,大多数据情况是配置在router/index.js中实现,如下
  {
    path: '/system/dict-data',
    component: Layout,
    hidden: true,
    permissions: ['system:dict:list'],
    children: [
      {
        path: 'index/:dictId(\\d+)',
        component: () => import('@/views/system/dict/data'),
        name: 'Data',
        meta: { title: '字典数据', activeMenu: '/system/dict' }
      }
    ]
  },
如果遇到需要经常修改的情况,那么就不宜直接写死静态路由,这个时候我们就可以在菜单管理中配置动态路由。
 针对上述的情况,我们可以在菜单管理中新增配置以实现动态路由的效果。 其中关键属性,路由名称为Data,路由地址为dict-data/index/:dictId(\d+),组件路径为system/dict/data,达到的效果是和上述静态路由配置是一致的。

如何使用横向菜单
默认的导航菜单都是在左侧,如果需要横向导航菜单可以做如下配置。
1、点击顶部最右侧个人中心头像,选择布局设置,开启TopNav。(局部设置)
2、在gyj-iot-web\src\settings.js,设置是否显示顶部导航topNav为true。(全局设置)
系统接口访问出现401
在测试系统接口中可能存在一些接口用到用户信息或权限验证,此时需要添加全局的token参数。如图

token是在登录成功后返回的,可以在浏览器通过F12查看Network中的请求地址,对应参数Authorization。复制截图内容到swagger全局Authorization属性value参数中,点击Authorize,以后每次访问接口会携带此token信息。

如何更换后端请求地址
在vite.config.js中,修改target值为对应的的后端接口地址。
server: {
  ...,
  proxy: {
	'/dev-api': {
	  target: 'http://localhost:8080',
	  ...
	}
  }
},
如何启动项目https协议
通常情况下,在启动本地项目时,默认都是http协议,但是有时候测试网站要求我们的协议是https,那么可以配置vite.config.js中的server,让其在启动项目的时候,默认是https协议。
server: {
  https: true,
  ......
},
如何获取用户登录信息
1.第一种方法
// 获取当前的用户名称
String username = SecurityUtils.getUsername();
2、缓存获取当前用户信息
@Autowired
private TokenService tokenService;
	
LoginUser loginUser = tokenService.getLoginUser();
// 获取当前的用户名称
String username = loginUser.getUsername();
3、vue3中获取当前用户信息
import useUserStore from '@/store/modules/user'
const userid = useUserStore().id;
const username = useUserStore().name;
提示您没有数据的权限
这种情况都属于权限标识配置不对在菜单管理配置好权限标识(菜单&按钮)
1.确认此用户是否已经配置角色
 2.确认此角色是否已经配置菜单权限
 3.确认此菜单权限标识是否和后台代码一致
- 例如参数配置查询权限
 1、后台Controller配置@PreAuthorize("@ss.hasPermi('system:config:query')")注解
 2、前端菜单管理/参数设置/参数查询权限字符应为system:config:query权限
注:如果是角色权限,应在前端角色管理配置对应角色的权限字符,后台使用@PreAuthorize("@ss.hasRole('admin')")注解
如何登录页面携带参数
有时候在未登录时需要访问需要登录的资源,并且需要在登录成功后传递请求参数。
// Vue3 版本的请求方式
http://localhost/login?redirect=system/user&id=123456&version=387
如何菜单配置路由传参
在菜单管理中选择菜单类型为菜单,填写对应的路由参数,如:{"id": 1, "name": "ry"}
在自己的组件中获取参数方式:this.$route.query.id,this.$route.query.name
如何默认显示顶部导航栏菜单
在gyj-iot-web\src\settings.js中设置topNav为true表示显示顶部导航,也可以在用户布局设置中开启TopNav后保存配置。
/**
* 是否显示顶部导航
*/
topNav: true,
如何修改超级管理员登录密码
1、如果是自己知道超级管理员的密码且需要修改的情况。 默认口令 admin/admin123,可以登录后在首页个人中心修改密码。
2、如果自己忘记了超级管理员的密码可以重新生成秘钥替换数据库密码。
public static void main(String[] args)
{
	System.out.println(SecurityUtils.encryptPassword("admin123"));
}
如何设置用户登录缓存超时时间
找到gyj-iot-boot\gyjiot-admin\src\main\resources下面的application.yml配置文件
# token配置
token:
    # 令牌有效期(默认30分钟)
    expireTime: 30
如何格式化前端日期时间戳内容
对应一些时间格式需要在前端进行格式化操作情况,解决方案如下
1、后端使用JsonFormat注解格式化日期,时间戳yyyy-MM-dd HH:mm:ss
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date time;
2、前端使用parseTime方法格式化日期,时间戳{y}-{m}-{d} {h}:{i}:{s}
<el-table-column label="创建时间" align="center" prop="createTime" width="160">
	<template slot-scope="scope">
	  <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
	</template>
</el-table-column>
登录页面如何不显示验证码
在菜单参数设置修改参数键名sys.account.captchaEnabled设置false即可。默认为true开启。
如何限制账户不允许多终端登录
这本来是一个可有可无的问题,不过经常有小伙伴有这样的需求。废话不多说,先来看同一用户不同终端限制登录的解决方法。方法很简单,大致思路就是做出userid与token(一个用户对应一个token,userid唯一)的键值对,存于缓存中。用于登录时判断用户是否在别的终端在线。详细实现代码如下:
1、application.yml新增一个配置soloLogin用于限制多终端同时登录。
# token配置
token:
    # 是否允许账户多终端同时登录(true允许 false不允许)
    soloLogin: false
2、Constants.java新增一个常量LOGIN_USERID_KEY公用
/**
 * 登录用户编号 redis key
 */
public static final String LOGIN_USERID_KEY = "login_userid:";
3、调整TokenService.java,存储&刷新缓存用户编号信息
// 是否允许账户多终端同时登录(true允许 false不允许)
@Value("${token.soloLogin}")
private boolean soloLogin;
/**
 * 删除用户身份信息
 */
public void delLoginUser(String token, Long userId)
{
	if (StringUtils.isNotEmpty(token))
	{
		String userKey = getTokenKey(token);
		redisCache.deleteObject(userKey);
	}
	if (!soloLogin && StringUtils.isNotNull(userId))
	{
		String userIdKey = getUserIdKey(userId);
		redisCache.deleteObject(userIdKey);
	}
}
/**
 * 刷新令牌有效期
 * 
 * @param loginUser 登录信息
 */
public void refreshToken(LoginUser loginUser)
{
	loginUser.setLoginTime(System.currentTimeMillis());
	loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
	// 根据uuid将loginUser缓存
	String userKey = getTokenKey(loginUser.getToken());
	redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
	if (!soloLogin)
	{
		// 缓存用户唯一标识,防止同一帐号,同时登录
		String userIdKey = getUserIdKey(loginUser.getUser().getUserId());
		redisCache.setCacheObject(userIdKey, userKey, expireTime, TimeUnit.MINUTES);
	}
}
private String getUserIdKey(Long userId)
{
	return Constants.LOGIN_USERID_KEY + userId;
}
4、自定义退出处理类LogoutSuccessHandlerImpl.java清除缓存方法添加用户编号
// 删除用户缓存记录
tokenService.delLoginUser(loginUser.getToken(), loginUser.getUser().getUserId());
5、登录方法SysLoginService.java,验证如果用户不允许多终端同时登录,清除缓存信息
// 是否允许账户多终端同时登录(true允许 false不允许)
@Value("${token.soloLogin}")
private boolean soloLogin;
	
if (!soloLogin)
{
	// 如果用户不允许多终端同时登录,清除缓存信息
	String userIdKey = Constants.LOGIN_USERID_KEY + loginUser.getUser().getUserId();
	String userKey = redisCache.getCacheObject(userIdKey);
	if (StringUtils.isNotEmpty(userKey))
	{
		redisCache.deleteObject(userIdKey);
		redisCache.deleteObject(userKey);
	}
}
如何修改Swagger默认访问地址
由于采用的前后端分离模式,且前端Swagger使用的iframe打开页面。所以默认请求的是前端地址,然后前端通过代理转发到后端接口。对于特殊情况需要直接请求后端提供如下方案:
方案1:使用新窗口打开,不要用iframe打开。因为swagger默认是获取当前服务的地址。
方案2:在SwaggerConfig配置中createRestApi方法设置后端的地址。
return new Docket(DocumentationType.SWAGGER_2)
    ....
	// 后端地址
    .host("localhost:8080")