练竹园何平安

Javaweb实战项目:公司信息管理系统(下)

Toretto·2023-08-28 03:42·37 次阅读

Javaweb实战项目:公司信息管理系统(下)


补充@ RequestBody注解:@RequestBody的使用_justry_deng的博客-CSDN博客,四种请求方式的区别:总结get、put、post、delete的区别和用法_get post put delete_云庄clouder的博客-CSDN博客

 

查询员工

跟之前查询部门一样的,直接EmpController写@GetMapping,Integer id,Emp emp=empService.getById(id);success(emp),然后后面就根据idea的提示非常简单。补充一下@RequestBody注解是将数据变为json格式的。

修改员工

在查询员工界面显示出来的修改数据

@PutMapping+@RequestBody(json格式数据传递)+update数据库语句+Service层自动补充更新时间变量。

XML中SQL语句:

<update id="update">
update emp
<set>
<if test="username != null and username != ''">
username = #{username},
</if>
<if test="password != null and password != ''">
password = #{password},
</if>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="gender != null">
gender = #{gender},
</if>
<if test="image != null and image != ''">
image = #{image},
</if>
<if test="job != null">
job = #{job},
</if>
<if test="entrydate != null">
entrydate = #{entrydate},
</if>
<if test="deptId != null">
dept_id = #{deptId},
</if>
<if test="updateTime != null">
update_time = #{updateTime}
</if>
</set>
where id = #{id}
</update>

配置文件

方式一:

还是为了方便操作,由于一个一个在类里面改参数很难找,所以就直接将参数定义在一个配置文件里面方便修改,比如OSS的accessKeyId,accessKeySecret,就用SpringBoot自己生成的application.properties拿来配置,比如我要配置阿里云Access的ID:

application.properties里面:aliyun.oss.accessKeyId=xxxxxxxx

然后再在AliOSSutils类里面将定义的accessKeyId的值去掉,并在上面加上@Value(“${aliyun.oss.accessKeyId}”)

方式二:

使用yml进行配置,在resources文件夹下application.yml文件,yml配置时需要缩进,比如我要配置服务器端口号:

server:
port: 9000

@ConfigurationProperties注解

就是不用一个一个写@Value注解了,但是没多大用除非变量很多。方法就是在对应类的包下创建一个类,里面再定义private变量并加上@Date,@Component,@ConfigurationProperties(prefix = “aliyun.oss”)这里的prefix里面写配置文件里面的最后一个逗号(或yml里面的冒号)的前面的,比如我这里配置的是AliOSSUtils里面的bucketName,然后再在AliOSSUtils里面去掉原来的 bucketName并加上

@Autowired
private AliOSSProperties aliOSSProperties;

然后再在方法里定义String bucketName=aliOSSProperties.getBucketName();

—-登录系统—-#

在Controller层创建一个 LoginController类专门用来登录,里面加上基本的@RestController等注解,然后登录请求方式为POST,需要传递Emp的参数,就Emp e=empService.login(emp);最后返回值为:(然后跟以前一样依样画葫芦)

return e!=null?Result.success():Result.error("用户名或密码错误");

EmpMapper里面的Select语句:

@Select("select *from emp where username=#{username} and password=#{password}")

登录校验#

防止登录后再次登录不用输密码,就需要登录校验。使用统一拦截技术可以不用在每个接口都写 if语句,

会话技术:用户打开浏览器访问服务器,会话建立,直到一方断开连接,会话结束,在一次会话中可以包含多次请求和响应。

会话跟踪:维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便同一次会话的多次请求间共享数据。

会话跟踪技术防止白雪,直接不学原始的Cookie和Session方式,直接学JWT令牌技术


Maven接口下载:Maven Repository: io.jsonwebtoken » jjwt » 0.9.1 (mvnrepository.com)

JWT官网:JSON Web Tokens – jwt.io

先来看代码:

@Test
public void testJWT(){
Map<String, Object> cliams=new HashMap<>();
cliams.put("id",1);
cliams.put("name","何平安");
String jwt=Jwts.builder()
.signWith(SignatureAlgorithm.HS256,"hepingan")//签名算法
.setClaims(cliams)//自定义内容
.setExpiration(new Date(System.currentTimeMillis()+3600*100))//设置令牌有效期为1h
.compact();
System.out.println(jwt);
}

三个参数,第一个signWith参数直接输HS256回车自动生成,这是JWT官网提供的算法生成,也有其他类型的算法看官网了,后面那个是密钥

setClaims里面输入自定义内容,可以是Map集合,然后算法会自动将他转换成字符,setExpiration设置令牌有效期,最后加上.compact();输出后结果复制到JWT官网就可以解码了:

在Java代码里面解码:

@Test
public void testParseJWT(){
Claims claims= Jwts.parser()
.setSigningKey("hepingan")//密钥
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5L2V5bmz5a6JIiwiaWQiOjEsImV4cCI6MTY5Mjk3MjYxOH0.gJmcR4cuPNWU9hmuLXm8ucpAJFqZNTe_oqstc0Cb-9k")
.getBody();
System.out.println(claims);
}

用JWT自带的Claims类来输出数据, 第一个是密钥,然后是码,getBody是获取整个码(getHeader是获取算法方法)。

应用到项目中

在utils软件包下粘贴下面的代码:(就是刚刚写的东西)

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtils {

private static String signKey = "itheima";
private static Long expire = 43200000L;

/**
 * 生成JWT令牌
 * @param claims JWT第二部分负载 payload 中存储的内容
 * @return
 */
 public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signKey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}

/**
 * 解析JWT令牌
 * @param jwt JWT令牌
 * @return JWT第二部分负载 payload 中存储的内容
 */
 public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}

然后再在之前的login 接口改成:

@PostMapping("/login")
public Result login(@RequestBody Emp emp){
log.info("员工登录:{}",emp);
Emp e=empService.login(emp);

if(e!=null){
Map<String, Object> claims=new HashMap<>();
claims.put("id",emp.getId());
claims.put("name",emp.getName());

String jwt=JwtUtils.generateJwt(claims);
return Result.success(jwt);
}
return Result.error("用户名或密码错误");
}

这样在以后每一次请求时都会先看 JWT令牌,按F12–>网络–>请求–>dept里找到Token就可以看到令牌了。

—Filter—#

过滤器,可以把请求拦截下来,只有经过过滤器才能请求。(就是网络安全类的)

先定义一个 Filter类,然后加上@WebFilter注解,配置拦截资源路径,引导类(启动类)加上@ServletComponentScan注解开启Servlet组件支持。

Filter 类单独创建个包在top.hepingan下吧,implements的Filter记住要选 servlet,(import jakarta.servlet.*;)然后直接实现三个方法。

@WebFilter(urlPatterns = “/*”)是指拦截全部请求。然后限制运行再去请求直接全部拦截了。

所以就需要添加放行操作:

filterChain.doFilter(servletRequest,servletResponse);//放行

一个WEB程序可以有多个filter,执行循序根据类型顺序(A,B,C…排下去)。

应用到案例当中去:

先看源码(类在filter软件包下)

@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
HttpServletResponse response=(HttpServletResponse) servletResponse;

//获取请求url
 String url= request.getRequestURL().toString();
log.info("请求的url:"+url);

//判断url是否存在login,如果有放行
 if (url.contains("login")){
log.info("登录操作,放行...");
filterChain.doFilter(request,response);
return;
}

//判断令牌是否存在
 String jwt=request.getHeader("token");
if(!StringUtils.hasLength(jwt)){
log.info("请求头token为空,返回未登录的信息");
Result error=Result.error("NOT_LOGIN");
String notLogin=JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return;
}

//解析 token
 try {
JwtUtils.parseJWT(jwt);
}catch (Exception e){
e.printStackTrace();
log.info("解析令牌失败,返回未登录错误信息");
Result error=Result.error("NOT_LOGIN");
String notLogin=JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return;
}

log.info("令牌合法,放行");
filterChain.doFilter(request,response);

}
}

先获取请求的url,就是请求方法的https地址,然后解析里面有没有login,因为登录操作不用解析令牌就直接放行,然后解析令牌头是否存在,如果存在就解析整个令牌,如果令牌合法就放行。错误则给前端返回”NOT_LOGIN”.

—Interceptor–#

拦截器,跟过滤器差不多的,用来动态拦截控制器的执行。

快速入门

先定义拦截器:创建类:Interceptor.LoginCheckInterceptor,接口:HandlerInterceptor,然后按crtrl+O重写全部方法,第一个是目标资源方法运行前放行,第二个是标资源方法运行后运行,第三个是视图渲染完毕后运行,最后运行。然后再在top.hepingan下创建类:config.WebConfig,里面接口:WebMvcConfiguer,然后实现方法:addInterceptors,然后注册一个拦截器:private LoginCheckInterceptor loginCheckInterceptor;然后再在实现方法里面改为:registry.addInterceptor(loginCheckInterceptor).addPathPatterns(“/**”);

注意在Interceptor里面调用全部请求为/**,Filter里面为/*,然后将之前的 Filter的@WebFilter注释掉防止冲突,最后启动项目,就之前Filter那个 login请求发送就ok。

拦截路径:‘/*’为一级路径,只能拦截/dept,/emp的请求,/dept/1就不能拦截。’/**’为全部拦截,啥都能匹配。/depts/**则是/depts下的全部路径,/depts/*则是depts下的一级路径。

Filter与Interceptor的关系:

实操到项目

只修改Interceptor的第一个实现方法:跟Filter的差不多,先复制过来然后去掉定义的Http的变量,然后放行就把return值设为true,不放行设置为false。

@Override//目标资源方法运行前放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...");
//获取请求url
 String url= request.getRequestURL().toString();
log.info("请求的url:"+url);

//判断url是否存在login,如果有放行
 if (url.contains("login")){
log.info("登录操作,放行...");
return true;
}

//判断令牌是否存在
 String jwt=request.getHeader("token");
if(!StringUtils.hasLength(jwt)){
log.info("请求头token为空,返回未登录的信息");
Result error=Result.error("NOT_LOGIN");
String notLogin= JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return false;
}

//解析 token
 try {
JwtUtils.parseJWT(jwt);
}catch (Exception e){
e.printStackTrace();
log.info("解析令牌失败,返回未登录错误信息");
Result error=Result.error("NOT_LOGIN");
String notLogin=JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return false;
}

log.info("令牌合法,放行");
return true;
}

这个时候再去访问网址就直接返回到登录界面了。

—异常处理—#

目前存在的异常:往新增部门新增相同的名字的部门,会发现浏览器没反应(原因就是SQL语句创建name的时候已设置为unique,不能重复)。

这时就往top.hepingan包下创建类Exception.GlobalException,然后里面编写:

@RestControllerAdvice
public class GlobalException {
@ExceptionHandler(Exception.class)
public Result ex(Exception exception){
exception.printStackTrace();
return Result.error("操作失败,请联系何平安~");
}
}

Exception.class是指捕获全部异常,也可以改成其他的什么IOEx啥的。

posted @   何平安  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
浏览器标题切换end
点击右上角即可分享
微信分享提示
目录