您的位置:首页 > 新闻 > 资讯 > 网页设计中界面设计尺寸为_徐州网站推广公司_网页在线客服免费版_百度关键词优化词精灵

网页设计中界面设计尺寸为_徐州网站推广公司_网页在线客服免费版_百度关键词优化词精灵

2025/3/14 18:48:53 来源:https://blog.csdn.net/weixin_40017062/article/details/146202173  浏览:    关键词:网页设计中界面设计尺寸为_徐州网站推广公司_网页在线客服免费版_百度关键词优化词精灵
网页设计中界面设计尺寸为_徐州网站推广公司_网页在线客服免费版_百度关键词优化词精灵

4.4.6 SpringBoot 解决跨域问题 CorsConfig

访问地址 http://localhost:7000/login
在这里插入图片描述

输入用户名、密码、验证码后,访问后端地址 http://localhost:9090/login跨域访问报错:
在这里插入图片描述

上一节给出解决方案Controller 类加个注解 @CrossOrigin,但每次新增 Controller 类都需要手工添加注解,比较麻烦。SpringBoot 提供过滤器 CorsFilter 统一处理 跨域访问 问题。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;@Configuration
public class CorsConfig {// 当前跨域请求最大有效时长。这里默认1天private static final long MAX_AGE = 24 * 60 * 60;@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法corsConfiguration.setMaxAge(MAX_AGE);source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置return new CorsFilter(source);}
}

4.4.7 后端接口

WebController

@RestController
public class WebController {@ResourceUserService userService;@PostMapping("/login")public Result login(@RequestBody User user) {System.out.println(user);if (StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) {return Result.error("数据输入不合法");}user = userService.login(user);return Result.success(user);}@PostMapping("/register")public Result register(@RequestBody User user) {if (StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) {return Result.error("数据输入不合法");}if (user.getUsername().length() > 10 || user.getPassword().length() > 20) {return Result.error("数据输入不合法");}user = userService.register(user);return Result.success(user);}
}

UserServiceImpl

@Override
public User login(User user) {// 根据用户名查询数据库的用户信息User dbUser = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, user.getUsername()));if (dbUser == null) {// 抛出一个自定义的异常throw new ServiceException("用户名或密码错误");}if (!user.getPassword().equals(dbUser.getPassword())) {throw new ServiceException("用户名或密码错误");}// 生成tokenString token = TokenUtils.createToken(dbUser.getId(), dbUser.getPassword());dbUser.setToken(token);return dbUser;
}@Override
public User register(User user) {User dbUser = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, user.getUsername()));if (dbUser != null) {// 抛出一个自定义的异常throw new ServiceException("用户名已存在");}user.setName(user.getUsername());userMapper.insert(user);return user;
}

自定义异常 ServiceException

@Getter
public class ServiceException extends RuntimeException {private final String code;public ServiceException(String msg) {super(msg);this.code = "500";}public ServiceException(String code, String msg) {super(msg);this.code = code;}}

GlobalException

@ControllerAdvice
public class GlobalException {@ExceptionHandler(ServiceException.class)@ResponseBodypublic Result serviceException(ServiceException e) {return Result.error(e.getCode(), e.getMessage());}}

4.5 SpringBoot集成JWT token实现权限验证

4.5.1 pom.xml添加JWT依赖

<!-- JWT -->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.3.0</version>
</dependency>

4.5.2 工具类 TokenUtils

@Component
public class TokenUtils {private static UserMapper staticUserMapper;@ResourceUserMapper userMapper;@PostConstructpublic void setUserService() {staticUserMapper = userMapper;}/*** 生成token** @return*/public static String createToken(String userId, String sign) {return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷.withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期.sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥}/*** 获取当前登录的用户信息** @return user对象*/public static User getCurrentUser() {try {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String token = request.getHeader("token");if (StrUtil.isNotBlank(token)) {String userId = JWT.decode(token).getAudience().get(0);return staticUserMapper.selectById(Integer.valueOf(userId));}} catch (Exception e) {return null;}return null;}
}

4.5.3 login() 方法增加 token 返回

@Override
public User login(User user) {// 根据用户名查询数据库的用户信息User dbUser = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, user.getUsername()));if (dbUser == null) {// 抛出一个自定义的异常throw new ServiceException("用户名或密码错误");}if (!user.getPassword().equals(dbUser.getPassword())) {throw new ServiceException("用户名或密码错误");}// 生成tokenString token = TokenUtils.createToken(String.valueOf(dbUser.getId()), dbUser.getPassword());dbUser.setToken(token);return dbUser;
}

Login.vue 将返回 token 存储本地

login() {
this.$refs["loginRef"].validate((valid) => {if (valid) {// 验证通过this.$request.post("/login", this.user).then((res) => {if (res.code === "200") {// 登录成功,跳转到首页this.$router.push("/");this.$message.success("登录成功");localStorage.setItem("honey-user", JSON.stringify(res.data.token)); // 存储 token 到本地} else {this.$message.error(res.msg);}});}
});

在这里插入图片描述
登录成功后,本地存储数据:

在这里插入图片描述

📌前端接口在每次请求后端数据的时候,都会在请求头带上这个 token 作为验证信息。

📅 request.js:
请求拦截器:对请求头增加 token

request.interceptors.request.use(config => {config.headers['Content-Type'] = 'application/json;charset=utf-8';// 设置请求头,增加tokenlet token = JSON.parse(localStorage.getItem("honey-user") || '{}')config.headers['token'] = tokenreturn config;
}

响应拦截器:判断权限不足,重定向登录页面

request.interceptors.response.use(response => {let res = response.data;// 兼容服务端返回的字符串数据if (typeof res === 'string') {res = res ? JSON.parse(res) : res}// 拦截权限不足的请求,重定向登录页面,防止直接输入网址访问if (res.code === '401') {router.push('/login')}return res;}
)

如果不登录直接访问 http://localhost:7000/ ,后台接口返回错误码 401,会被响应拦截器拦截,重定向到登录页面。登录完成后,本地存储 token,后续访问后端请求从本地存储获取到 token,才能正常访问。

4.5.4 自定义注解 AuthAccess

import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthAccess {
}

该注解用于标注权限放行的方法。

@AuthAccess
@PostMapping("/register")
public Result register(@RequestBody User user) {if (StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) {return Result.error("数据输入不合法");}if (user.getUsername().length() > 10 || user.getPassword().length() > 20) {return Result.error("数据输入不合法");}user = userService.register(user);return Result.success(user);
}

WebController 的方法 register() 标注注解 @AuthAccess,结合下面拦截器 JwtInterceptor 对该注解的处理,register() 方法将被放行。

4.5.5 自定义拦截器 JwtInterceptor

public class JwtInterceptor implements HandlerInterceptor {@Resourceprivate UserMapper userMapper;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String token = request.getHeader("token");if (StringUtils.isBlank(token)) {token = request.getParameter("token");}// 对标注 AuthAccess 注解的方法进行放行if (handler instanceof HandlerMethod) {AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class);if (annotation != null) {return true;}}// 判断前端上送 token,执行认证if (StringUtils.isBlank(token)) {throw new ServiceException("401", "请登录");}// 获取 token 中的 user idString userId;try {userId = JWT.decode(token).getAudience().get(0);} catch (JWTDecodeException j) {throw new ServiceException("401", "请登录");}// 根据token中的userid查询数据库User user = userMapper.selectById(userId);if (user == null) {throw new ServiceException("401", "请登录");}// 用户密码加签验证 tokenJWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();try {jwtVerifier.verify(token); // 验证token} catch (JWTVerificationException e) {throw new ServiceException("401", "请登录");}return true;}
}

📌 请求头获取 token 字段值,进行JWT 认证判断是否为登录成功生成的 token ,进而进行权限认证。

💦if (handler instanceof HandlerMethod) 的含义是什么?

1.springmvc 启动时候,扫描所有 controller 类,解析所有映射方法,将每个映射方法封装一个对象 HandlerMethod ,该类包含所有请求映射方法信息(映射路径 / 方法名 / 参数 / 注解 / 返回值),上例中 AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class),就是获取请求方法是否标注 AuthAccess 注解。
2.springmvc 针对这些请求映射方法信息封装对象类,使用类似 map 的数据结构进行统一管理 Map<String, HandlerMethod> map
3.页面发起请求时(/users/currentUser),进入拦截器之后,springmvc 自动解析请求路径,得到 url(/users/currentUser),获取url之后,进而获取 /users/currentUser 路径对应的映射方法 HandlerMethod 实例
4.调用拦截器 preHandle 方法并将请求对象、响应对象、映射方法对象 handler 一起传入。
📖 登录拦截器原理

1.在Spring MVC中,拦截器的preHandlepostHandleafterCompletion方法的第三个参数是一个 Object 类型的 handler 参数。这个 handler 参数实际上就是处理当前请求的处理器。
2.在Spring MVC中,处理器不一定是 HandlerMethod 类型的。例如,当请求的URL对应的是一个静态资源时,处理器可能是ResourceHttpRequestHandler类型的。
3.因此,如果你的拦截器的代码只适用于 HandlerMethod 类型的处理器,你需要在代码中加入 if (handler instanceof HandlerMethod)这样的判断,以确保代码不会在处理其他类型的处理器时出错。
4.在Spring MVC中,HandlerMethod 是一个特殊的处理器类型,它用于处理由 @RequestMapping 注解(或其变体,如@GetMapping、@PostMapping等)标注的方法。
📖 Springmvc拦截器的时候要加判断 handler instanceof HandlerMethod

4.5.6 配置拦截器 InterceptorConfig

@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {@Overrideprotected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor()).addPathPatterns("/**")         // 1. 设置拦截路径.excludePathPatterns("/login"); // 2. 设置放行路径super.addInterceptors(registry);}@Beanpublic JwtInterceptor jwtInterceptor() {return new JwtInterceptor();}
}

.addPathPatterns("/**"):对所用请求地址进行拦截
.excludePathPatterns("/login"):设置放行路径,此处对 /login 进行放行,不进行拦截处理,即不校验 token。如果想对整个路径放行,可以设置 /login/**,即对 /login 下所有路径放行。

  • .excludePathPatterns(url) 和 注解 @AuthAccess 结合使用,可以灵活设置放行方法。

4.6 单文件、多文件上传和下载

4.6.1 文件上传、下载 Java 代码

@RestController
@RequestMapping("/file")
public class FileController {@Value("${ip:localhost}")String ip;@Value("${server.port}")String port;private static final String ROOT_PATH =  System.getProperty("user.dir") + File.separator + "files";@PostMapping("/upload")public Result upload(MultipartFile file) throws IOException {// 文件的原始名称String originalFilename = file.getOriginalFilename();// 获取文件名称、后缀名String mainName = FileUtil.mainName(originalFilename);String extName = FileUtil.extName(originalFilename);// 如果当前文件的父级目录不存在,就创建if (!FileUtil.exist(ROOT_PATH)) {FileUtil.mkdir(ROOT_PATH);}// 如果当前上传的文件已经存在了,那么重命名一个文件if (FileUtil.exist(ROOT_PATH + File.separator + originalFilename)) {originalFilename = System.currentTimeMillis() + "_" + mainName + "." + extName;}File saveFile = new File(ROOT_PATH + File.separator + originalFilename);// 存储文件到本地的磁盘里面去file.transferTo(saveFile);String url = "http://" + ip + ":" + port + "/file/download/" + originalFilename;// 返回文件的链接,这个链接就是文件的下载地址,这个下载地址就是我的后台提供出来的return Result.success(url);}@AuthAccess@GetMapping("/download/{fileName}")public void download(@PathVariable String fileName, HttpServletResponse response) throws IOException {// 附件下载response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));// 预览// response.addHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(fileName, "UTF-8"));String filePath = ROOT_PATH  + File.separator + fileName;if (!FileUtil.exist(filePath)) {return;}byte[] bytes = FileUtil.readBytes(filePath);ServletOutputStream outputStream = response.getOutputStream();outputStream.write(bytes);outputStream.flush();outputStream.close();}
}

在这里插入图片描述

在这里插入图片描述

📅 响应头 Content-Dispositionattachment;filename=,文件以附件形式下载;

在这里插入图片描述

📅Content-Dispositioninline;filename=,图片和 pdf 可以预览,其他文件类型还是以附件形式下载。

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com