疫情防控交流社区平台——2.3 开发社区登录注册模块

本文档详细介绍了使用Spring Boot开发社区登录注册模块及账号设置功能,包括访问账号设置页面、上传和获取头像的实现,以及通过自定义注解和拦截器检查登录状态。通过@Controller、@RequestMapping、@Service等注解进行功能划分,使用MultipartFile处理文件上传,同时利用拦截器LoginRequired确保用户已登录。
摘要由CSDN通过智能技术生成

🌕开发社区登录注册模块

6.账号设置

在这里插入图片描述

上传文件前两点是硬性要求,图片存储到服务器上,之后换到云服务器上。

6.1 访问账号设置页面

6.1.1 UserController新建
@Controller
@RequestMapping("/user")//窄化请求
public class UserController {

    //跳转设置页的请求
    @RequestMapping(path = "/setting",method = RequestMethod.GET)
    public String getSettingPage(){
        return "/site/setting";
    }
}
6.1.2 setting和index页面的修改

在这里插入图片描述

6.1.3 测试

前端页面确实能够跳转了!这一步很简单!

6.2 🍊上传头像和获取头像

6.2.1 application.properties
  • 配置文件上传资源所在的位置
#配置上传文件资源的位置   开发的时候在本机,上线后在linux上
community.path.upload=D:/1920.1080/UPLOAD
6.2.2 UserService

直接去业务层写上传逻辑,与数据访问层没关系,因为不和数据库打交道。
业务层只处理更新文件路径的需求(改变头像),上传文件的事在controller表现层里面进行,因为MultipartFile是属于MVC中的,如果又在service操作它,耦合度比较高,不合适。

	//更新用户头像
    public int updateHeaderByUserId(int userId,String header){
        return userMapper.updateHeader(userId, header);
    }
6.2.3 UserController
	private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    //注入参数
    @Value("${community.path.domain}")
    private String domain;
    @Value("${community.path.upload}")
    private String uploadPath;
    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Autowired
    private UserService userService;
    @Autowired
    private HostHolder hostHolder;  //更新的是哪个用户的头像,可以从hostHolder来取,相当于session

	//❤上传头像
    @RequestMapping(path = "/upload",method = RequestMethod.POST)
    public String uploadHeader(MultipartFile headerImage, Model model){
        //1.先判断
        if (headerImage == null){
            model.addAttribute("error","您还没有选择图片!");
            return "/site/setting";
        }

        //2.判断后缀合不合理
        //存的图片不能按原始名称存,比如1.png,我存到硬盘就不能这名字;因为可能很多人传的名字都是1.png,就会冲突覆盖。一般随机生成名字,后缀不能改变
        String filename = headerImage.getOriginalFilename();    //- 获取图片原始名
        String suffix = filename.substring(filename.lastIndexOf("."));//- 截取文件名的最后一部分,“.”代表分割线,“lastIndexOf”代表取分割之后的,就是文件后缀名
        if (StringUtils.isBlank(suffix)) {  //判断空,因为可能文件就是没有后缀名
            model.addAttribute("error", "图片格式不正确!");
            return "/site/setting";
        }

        //3.生成随机文件名并带上后缀
        filename = CommunityUtil.generateUUID() + suffix;
        //确定文件存放的路径
        File dest = new File(uploadPath + "/" + filename);
        //存储文件 —— 将headerImage数据写入到这个dest中
        try {
            headerImage.transferTo(dest);
        } catch (IOException e) {
            logger.error("上传文件失败 " + e.getMessage());
            throw new RuntimeException("上传文件失败,服务器发送异常!", e);
        }

        //4.更新当前用户头像路径 —— 存成功后,更新头像路径(web访问路径)  比如什么e盘那个文件夹是不行的,别人不在我们电脑上
        //http://localhost:8080/community/user/header/xxx.png
        User user = hostHolder.getUsers(); //直接从hostHolder获取 —— 持有用户信息,用于代替session对象
        String headerUrl = domain + contextPath + "/user/header/" + filename; //新路径
        userService.updateHeaderByUserId(user.getId(), headerUrl);
        return "redirect:/index";
    }

	//❤获取头像 —— 和上面新路径相关
    @RequestMapping(path = "/header/{filename}", method = RequestMethod.GET)
    //为什么是void,因为比较特别;它向浏览器响应的不是一个网页或字符串,而是一个图片,是二进制的数据
    //需要通过流手动向浏览器输出,所以返回值void,直接手动调用response往外面写就可以了
    public void getHeader(@PathVariable("filename") String filename, HttpServletResponse response) {
        //服务器存放路径
        filename = uploadPath + "/" + filename;
        //文件后缀解析
        String suffix = filename.substring(filename.lastIndexOf("."));
        //响应图片
        response.setContentType("image/" + suffix);
        try (
                //这种方法就是业务完成后,不需要手动去close资源,会自动帮我们,前提是有close方法
                OutputStream os = response.getOutputStream();//得到输出流
                FileInputStream fis = new FileInputStream(filename);//得到输入流
        ) {
            //OutputStream os = response.getOutputStream();//得到输出流
            //FileInputStream fis = new FileInputStream(filename);//得到输入流
            //有了输入流,就开始输出了
            byte[] buffer = new byte[1024];
            int a = 0;
            while ((a = fis.read(buffer)) != -1) {
                //不等于-1,表示读到数据了
                os.write(buffer, 0, a);
            }
        } catch (IOException e) {
            logger.error("读取头像失败 " + e.getMessage());
        }

    }
6.2.4 setting.html页面改造
6.2.5 测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

成功!

7.检查登录状态

在这里插入图片描述

比如用户知道设置头像的url路径,能直接通过地址栏跳转过去,这是不安全的!
所以拦截器能拦截这种行为,之前是通过配置文件在里面设置通行路径挨个指定,这次使用注解的方式!

  • 想拦截哪个方法,就在方法上加一个注解,加了就拦截,不加不拦截

注解自己定义,并且怎么去识别 —— 关键
如果自己想定义个注解,就要用元注解定义我们自己注解-
@Target —— 用来声明我们自定义的注解可以用在哪个位置,可以作用在哪个类型上;比如类上,方法上,属性上;- @Retention —— 用来声明自定义注解所保留的时间或有效的时间;比如编译时有效,还是运行时有效-
@Document —— 用来声明我们自定义注解在我们生成文档的时候要不要把它带进去-
@Inherited —— 用来继承的,比如子类继承父类,父类上有这个自定义注解,子类要不要把这个注解也注入进来,由它指定;
Method.getDeclaredAnnotations() —— 获取这个方法之上所有的注解
Method.getAnnotation(Class《T》 annotationClass) —— 获取这个类型的注解

7.1 LoginRequired

第一步,先把注解定义好,这个比较简单。
新建一个包,annotation;
在这里插入图片描述

@Target(ElementType.METHOD)   //注解可以写在方法之上,用来描述方法
@Retention(RetentionPolicy.RUNTIME)  //表程序运行时有效
public @interface LoginRequired {
    
}

然后在响应的controller上加入这个注解,表示只有登录才能访问
在这里插入图片描述
在这里插入图片描述
加上以后,就要用拦截器来拦截带有注解的方法,拦截到方法以后,判断有没有登录。登陆了可以,没有就拒绝;然后写一个拦截器处理后续的逻辑;
在这里插入图片描述

7.2 LoginRequiredInterceptor

@Component
public class LoginRequiredInterceptor implements HandlerInterceptor {
    @Autowired
    private HostHolder hostHolder;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //先判断hander是不是属于方法;比如静态资源就不用拦截
        if (handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod) handler;  //转型
            Method method = handlerMethod.getMethod();
            LoginRequired loginRequired = method.getAnnotation(LoginRequired.class);
            //判断loginRequired
            if (loginRequired != null && hostHolder.getUsers() == null){
                response.sendRedirect(request.getContextPath()+"/login");
                return false;
            }
        }
        return true;
    }
}

7.3 WebMvcConfig

	@Autowired
    private LoginRequiredInterceptor loginRequiredInterceptor;
	@Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginRequiredInterceptor)  //全部拦截
                .excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg"); //放行的资源
    }

7.4 测试

在这里插入图片描述
然后就会拦截并跳转到 登录页面:
在这里插入图片描述
然后:
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

11_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值