Java日常开发中的问题以及解决方案
SpringBoot篇
jdk与SpringBoot版本不兼容问题
启动项目时报错如下:
java.lang.UnsupportedClassVersionError:org/springframework/boot/loader/JarLauncher : Unsupported major.minor version 52.0
一般jdk1.8 -----> springboot 2.5.x以下
jdk1.9 -----> springboot2.5.x以上
静态资源访问异常问题(404)
-
问题描述
-
问题原因
springboot的默认资源访问路径如下,资源放在其他文件夹下访问不到。
-
解决办法
1 把资源放在以上默认文件夹下
2 在application.yml配置文件中配置静态资源访问路径
或者
修改后访问正常
SpringBoot中登录与权限认证
登录
所用技术与框架:
JWT + Redis + Spring拦截器
设计思路
login请求:前端传来username和password,后台进行验证,验证通过之后根据用户id和用户名使用JWT技术生成用户唯一token,同时将用户信息缓存到Redis中,并且设置过期时间,返回token给前端。
其他请求:前端携带保存于header中的token,后端的前置拦截器preHandler()方法中获取token后验证token合法性,再通过token获取用户信息,根据用户id和用户名查询Redis中是否存在用户信息 ,存在则放行。
实现流程:
权限处理
数据库设计
权限表
角色表
用户表
设计思路
1. 创建注解@AuthRequired 和权限拦截器PermissionIntercepter
2. 前端发送请求被springboot的权限拦截器PermissionIntercepter拦截。
3. 权限拦截器中通过反射获取拦截的方法的信息,判断方法上是否存在@AuthRequired注解,不存在就直接放行。
4. 存在即根据token获取用户的权限列表,与request.getUrl()对比,用户存在该权限就放行,不存在就拦截。
代码实现
权限拦截器代码
package com.cngrain.website.interceptor;
import com.cngrain.website.annotation.AuthRequired;
import com.cngrain.website.common.utils.JwtUtils;
import com.cngrain.website.common.utils.RedisUtil;
import com.cngrain.website.entity.User;
import com.cngrain.website.interceptor.exception.WebsiteException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
@Component
public class PermissionInterceptor implements HandlerInterceptor {
@Autowired
RedisUtil redisUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 如果不是映射到方法不拦截 直接通过
if (!(handler instanceof HandlerMethod)) {
return true;
}
//获取用户Id
String id = JwtUtils.getMemberIdByJwtToken(request);
User user = (User) redisUtil.get("website:user:info" + id);
if(user.getRoles().equals("admin")) {//admin 最高权限
return true;
}
//通过反射, 获取方法和和方法上的注解信息
Method method = ((HandlerMethod) handler).getMethod();
Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
Boolean authRequired = false;
for (Annotation annotation : declaredAnnotations) {
if(annotation.annotationType() == AuthRequired.class) {
authRequired = true;
break;
}
}
if(authRequired) {
//请求的url
String requestURI = request.getRequestURI();
//获取用户的权限列表,存在redis中的
Set<String> set =(HashSet) redisUtil.get("website:user:permission" + id);
if(set.contains(requestURI)) { //有权限
return true;
}
throw new WebsiteException(201,"权限不足");
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
}
登录代码
package com.cngrain.website.service.impl;
import com.cngrain.website.common.Result;
import com.cngrain.website.common.utils.JwtUtils;
import com.cngrain.website.common.utils.RedisUtil;
import com.cngrain.website.entity.Permission;
import com.cngrain.website.entity.Role;
import com.cngrain.website.entity.User;
import com.cngrain.website.interceptor.exception.WebsiteException;
import com.cngrain.website.mapper.PermissionMapper;
import com.cngrain.website.mapper.RoleMapper;
import com.cngrain.website.mapper.UserMapper;
import com.cngrain.website.service.LoginService;
import com.cngrain.website.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.Set;
@Service
public class LoginServiceImpl implements LoginService {
@Autowired
RedisUtil redisUtil;
@Autowired
UserService userService;
@Autowired
UserMapper userMapper;
@Autowired
RoleMapper roleMapper;
@Autowired
PermissionMapper permissionMapper;
@Override
public Result login(String username, String password) {
User one = userMapper.getByUsernamePassword(username,password);
if(one == null) {
throw new WebsiteException(201,"用户名或者密码错误");
}
//创建Set集合,用于存放权限url
Set<String> permissionSet = new HashSet<>();
//获取用户角色信息
String[] roles = one.getRoles().split(",");
for (String roleName : roles) {
Role role = roleMapper.getPermissionByRoleName(roleName);
//根据用户角色获取用户权限列表 格式--(1,2,3,4)存储的为权限id
String rolePermission = role.getRolePermission();
String[] split = rolePermission.split(",");
for (String id : split) {
if(id.equals("")) {
break;
}
//根据id获取权限url
Permission permission = permissionMapper.getPermissionUrlById(Integer.valueOf(id));
permissionSet.add(permission.getPermissionUrl());
}
}
//生成token
String token = JwtUtils.getJwtToken(one.getId().toString(),one.getName());
//redis存储用户信息,设置过期时间
redisUtil.set("website:user:info" + one.getId(),one,3000);
//将权限集合存放到redis中
redisUtil.set("website:user:permission" + one.getId().toString(),permissionSet);
// 返回token
return Result.ok().data("token",token);
}
}
拦截器配置代码
package com.cngrain.website.config;
import com.cngrain.website.interceptor.LoginInterceptor;
import com.cngrain.website.interceptor.PermissionInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
LoginInterceptor loginInterceptor;
@Autowired
PermissionInterceptor permissionInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor) //登录拦截器
.addPathPatterns("/**") //拦截
.excludePathPatterns("/login/**","/register/**"); //放行登录与注册
registry.addInterceptor(permissionInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login/**","/register/**");
}
}
注解代码
package com.cngrain.website.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE}) //作用域 方法和类上
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthRequired {}
常用基础知识
获取当前springboot工程的classpath路径
ApplicationHome applicationHome = new ApplicationHome(this.getClass());
String classpath = applicationHome.getDir().getAbsolutePath()
Java基础篇
系统环境变量中配置了JAVA_HOME为1.8版本,与cmd窗口执行java -version版本信息不一致
检查path中的%JAVA_HOME%\bin的位置,一般是上面的环境变量中存在其他版本的jdk,解决办法:
1:%JAVA_HOME%\bin上移
2: 找出其他版本jdk位置然后删除
数据库篇
Oracle
新建数据库用户
先进入sqlshell页面
windows ) sqlplus
linux ) sqlplus '/as sysdba'
删除用户
drop user test1 cascade;
新建用户
create user test1 identified by test1 default tablespace users temporary tablespace temp;
分配权限
grant connect to test1;
grant resource to test1;
grant dba to test1;
alter user test1 quota unlimited on users;
导入导出数据库
查询当前所有连接(注意修改数据库名称)
select 'alter system kill session '''||sid ||','||serial#||''';',username,status from v$session where username='c4cwdb';
导入
imp c3cwdb/c3cwdb file=/home/oracle/quanhy/20231230_c3cwdb_1.dmp full=y
导出
exp c8cwdb/c8cwdb@app file=20231115_c8cwdb_0.dmp
开发工具篇
内存溢出错误java: Compilation failed: internal java compiler error
如图错误信息
解决方案:设置Shared build process heap size (Mbytes): 的值
补充:之前错误由于在windows环境使用了linux版本的jdk导致的
eclipse的SSH项目导入到idea中
eclipse 转 idea 的SpringBoot项目报错
加载不到配置文件/WEB-INF/decorators.xml
报错详情:
Cannot construct Factory : com.opensymphony.module.sitemesh.factory.DefaultFactory: java.lang.IllegalStateException:
Cannot load excludes configuration file "/WEB-INF/decorators.xml"
as specified in "sitemesh.xml" or "sitemesh-default.xml
解决方案:
配置Working directory为 $MODULE_WORKING_DIR$,如下图
Linux篇章
No space left on device错误
该错误是linux系统空间不足造成的,释放磁盘空间即可
新建用户
一般使用命令:sudo useradd -m -g root username,即可在home路径下新建用户名为username,所属组为root的用户。
`useradd` 是在 Linux 中用于创建用户的命令,它的常用参数有:
`-d /home/username` 设定用户的主目录,会在 /home 下新建一个和用户名同名的用户主目录。
`-m` 用来建立用户的主目录,如果不加这个参数,可能会导致用户主目录没有被创建。
`-s /bin/bash` 设定用户登录后所使用的 shell。
`-u UID` 设定用户的 UID。 UID 是对应用户的一个数字ID,系统内部使用这个 ID 进行管理,对用户来说,用户名才是重要的。
`-g GID` 设定用户所属的初始用户组。类似于 UID,GID 是用户组的数字ID。
`-G group1,group2` 设定用户所属的附加用户组。一个用户可以属于多个用户组。
`-p password` 设定用户的初始密码。需要注意的是,这里设定的密码并非明文密码,而是已进行加密的密码。
`-e yyyy-mm-dd` 设定用户的账号过期时间。
`-c "User Full Name"` 添加注释性描述。
idae中常用快捷键
ctrl + p -------------------------提示方法参数
ctrl + o -------------------------重写父类方法
shift + shift / ctrl + shift + r -全局搜索
开发中常用命令
df -h -----------------------------查看磁盘空间使用情况
tail -f xxxx.log ------------------动态查看文件信息
tail -n 100 xxxx.log --------------查看日志后100行
git clone xxxx.git ---------------拉取代码
git clone xxxx.git -b [分支名称] ---拉取指定分支代码
ls -lrt ---------------------------按时间排序查看文件
ps -ef | grep /opt/tomcat9/ -------查看指定文件夹下正在运行的tomcat程序