zoukankan      html  css  js  c++  java
  • Spring boot 论坛项目实战_02

    Spring Boot 实践,开发社区登录模块

    1.发送邮件

    • 邮箱设置

      • 启用客户端SMTP服务

      • 才用新浪邮箱,设置里面进行服务开启

    • Spring Email【集成在 Spring 中】

      • 导入 jar 包

        • <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-mail</artifactId>
              <version>2.1.5.RELEASE</version>
          </dependency>
      • 邮箱参数配置

        • 用配置文件,完成邮箱参数配置,不要一次性写死,便于后续更新

        • Application.properties 中配置

        • # MailProperties    
          # 使用的邮箱域名
          spring.mail.host=smtp.sina.com
          spring.mail.port=465
          spring.mail.username= 自己的邮箱用户名
          spring.mail.password= 自己的邮箱的 SMTP 授权码
          # 指定协议
          spring.mail.protocol=smtps
          # 其他详尽配置
          # 发送邮件的时候采用安全的 ssl 连接
          spring.mail.properties.mail.smtp.ssl.enable=true
      • 使用 JavaMailSender[Spring 的 Bean] 发送邮件

        • 如果出现: 身份认证错误[ 下面这种 ], 记得检查邮箱配置的 username 和 password

        • org.springframework.mail.MailAuthenticationException: Authentication failed;

        注意: 用 STMP 发送的文件, 在发送邮箱本身的已发送是看不到的.

    • 模板引擎

      • 使用Thymeleaf 发送 HTML 邮件

    2.开发注册功能

    • 访问注册页面

      • 点击顶部区域内的链接,打开注册页面

    • 提交注册数据

      • 通过表单提交数据

      • 服务端验证帐号是否已存在、邮箱是否已注册

        • 这里注意下,一定要保证数据库里的数据唯一性,不然会报错

      • 服务端发送激活邮件

    • 激活注册帐号

      • 点击邮件中的链接,访问服务端的激活服务

    3.会话管理

    • HTTP的基本性质

      • HTTP是简单的

      • HTTP是可扩展的

      • HTTP是无状态的,有会话的

        • 使用 Cookies 可以创建有状态的会话

    • Cookie【分布式,尽量用Cookie保存数据】

      • 是服务器发送到浏览器,并保存在浏览器端的一小块数据。

      • 浏览器下次访问该服务器时,会自动携带该块数据,并将其发送给服务器

      • // Cookie 示例
        ​
            @RequestMapping(path = "/cookie/set", method = RequestMethod.GET)
            @ResponseBody
            public String setCookie(HttpServletResponse response) {
                // 创建Cookie
                Cookie cookie = new Cookie("code", CommunityUtil.generateUUID());
                // 设置 Cookie 生效范围
                cookie.setPath("/community/alpha");
                // 设置 Cookie 生存时间, 默认 关闭浏览器就消失
                cookie.setMaxAge(60 * 10);// 单位秒
                // 发送 cookie
                response.addCookie(cookie);
        ​
                return "set cookie";
            }
        ​
            @RequestMapping(path = "/cookie/get", method = RequestMethod.GET)
            @ResponseBody
            public String getCookie(@CookieValue("code") String code){
                System.out.println(code);
                return "get cookie";
            }
    • Session【分布式中不方便存 Cookie 的数据,可以存在 NoSql 数据库中:Redis】

      • 是 JavaEE 的标准【API】,用于在服务端记录客户端信息

      • 数据存放在服务端更加安全,但是也会增加服务端的内存压力

      • // Session 示例
            @RequestMapping(path ="/session/set" , method = RequestMethod.GET)
            @ResponseBody
            public String setSession(HttpSession session){
                session.setAttribute("id",1);
                session.setAttribute("name","test");
                return "set session";
            }
        ​
            @RequestMapping(path ="/session/get" , method = RequestMethod.GET)
            @ResponseBody
            public String getSession(HttpSession session){
                System.out.println(session.getAttribute("id"));
                System.out.println(session.getAttribute("name"));
                return "get session";
            }

     

    4. 生成验证码

     

    package com.nowcoder.community.config;
    ​
    import com.google.code.kaptcha.Producer;
    import com.google.code.kaptcha.impl.DefaultKaptcha;
    import com.google.code.kaptcha.util.Config;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    ​
    import java.util.Properties;
    ​
    /**
     * Kaptcha 的配置类
     */
    ​
    @Configuration
    public class KaptchaConfig {
        
        @Bean
        public Producer kaptchaProducer(){
            Properties properties = new Properties();
            // 设置 kaptcha 的属性
            properties.setProperty("kaptcha.image.width","100");
            properties.setProperty("kaptcha.image.height","40");
            // 设置字号
            properties.setProperty("kaptcha.textproducer.font.size","32");
            properties.setProperty("kaptcha.textproducer.font.color","0,0,0");// R,G,B
                                        properties.setProperty("kaptcha.textproducer.char.string","1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ");
            properties.setProperty("kaptcha.textproducer.char.length","4");
            properties.setProperty("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");
    ​
    ​
            DefaultKaptcha kaptcha = new DefaultKaptcha();
            Config config = new Config(properties);
            kaptcha.setConfig(config);
            return kaptcha;
    ​
        }
    ​
    }
    #JS问题
    <!-- 原本刷新验证码方法失效 -->
    <a href="javascript:refresh_kaptcha();" class="font-size-12 align-bottom">刷新验证码</a>
    <script>
      function refresh_kaptcha() {
             var path = CONTEXT_PATH + "/kaptcha?p=" + Math.random();
             $("#kaptcha").attr('src', path);
         }
    </script><!-- 
        解决办法: 用点击实现验证码图片的 src 更新, 添加随机参数保证图片的刷新
    -->
    <a href="javascript:refresh_kaptcha();" onclick="changeImage()"  class="font-size-12 align-bottom">刷新验证码</a>
    <script>
        function changeImage(){
                var element = document.getElementById('kaptcha');
                var path = CONTEXT_PATH + "/kaptcha?p=" + Math.random();
                element.src = path;
            }
    </script>
     

    5.开发登录、退出功能

    • 访问登录页面

      • 点击顶部区域内的链接,打开登录页面

    • 登录

      • 验证帐号、密码、验证码

      • 成功时,生成登录凭证,发放给客户端

      • 失败时,跳转回登录页

    • 退出

      • 将登陆凭证更新为失效状态

      • 跳转至网站首页

     

    6. 显示登录信息

    • 拦截器示例

      • 定义拦截器,实现 HandlerInterceptor 接口

      • 配置拦截器,为它指定拦截、排除的路径

        • /**
           * 拦截器的配置类
           * implements WebMvcConfigurer
           * 实现这个接口
           */
          @Configuration
          public class WebMvcConfig implements WebMvcConfigurer {
          ​
              // 注入拦截器对象
              @Autowired
              private AlphaInterceptor alphaInterceptor;
          ​
              @Override
              public void addInterceptors(InterceptorRegistry registry) {
                  // 添加要注册的拦截器;
                  // 指定[排除]拦截路径, 若不指定则是拦截所有资源;
                  // 明确要拦截的路径
                  registry.addInterceptor(alphaInterceptor)
               /* 排除对静态资源的拦截*/           .excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg")
                      /*指定要拦截的 路径*/
                          .addPathPatterns("/register","/login");
              }
          }
        • 实现:

          1. 写一个类实现接口,根据实际情况写方法

          2. 配置拦截器,指定它拦截的请求

        • 优势:降低代码耦合

    • 拦截器应用

      • 在请求开始时,查询登录用户

        • // 在Controller之前执行
              @Override
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                  // 具体处理
                  logger.debug("preHandle: " + handler.toString());
                  return true;
              }

           

      • 在本次请求中持有用户数据

        • // 利用 ThreadLocal 保证多线程的并发安全: 
          // 	以线程[CurrentThread]为 Map 的key 来存取值
      • 在模板视图上显示用户数据

        • // 在Controller之后执行
              @Override
              public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
                  // 具体处理
                  logger.debug("postHandle: " + handler.toString());
              }
      • 在请求结束时清理用户数据

        • // 在TemplateEngine之后执行
              @Override
              public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
                  // 具体处理
                  logger.debug("afterCompletion: " + handler.toString());
              }

    7.账号设置

    • 上传文件

      • 请求:必须是POST 请求

      • 表单:添加属性 : enctype= “multipart/form-data”

      • Spring MVC:通过MultipartFile 处理上传文件

      • 注意需要先把上传路径的文件夹建好

    • 开发步骤

      • 访问帐号设置页面

      • 上传头像

      • 获取头像

     

    8.检查登陆状态

    • 使用拦截器

      • 在方法前标注自定义注解

      • 拦截所有请求,只处理带有该注解的方法

    • 自定义注解

      • 注解的类型是:

      • 常用的元注解:

        • // 定义自己声明的注解,可以用在哪个位置
          @Target
          // 声明自定义注解,保留或有效时间
          @Retention
          // 【下面两个非必须】
          // 声明自定义注解,在生成文档的时候要不要带上这个注解
          @Document
          // 用于继承,子类在继承父类时,要不要继承这个自定义注解
          @Inherited
      • 如何读取注解:

        • // 通过反射读取, 调用注解
          // 获取所有注解
          Method.getDeclaredAnnotations();
          // 按照类型获取这个类型的注解
          Method.getAnnotation(Class<T> annotationClass);
      • 注解的使用:

        • /*
          * 这个注解的位置 : 方法上面
          * 这个注解的有效期: 程序运行时
          */
          @Target(ElementType.METHOD)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface LoginRequired {
              // 这个注解就只起一个标识的作用
              // 声明这个方法,要在程序运行后才能访问
          }
  • 相关阅读:
    asp.net core 发布centos 7 遇到的坑
    模拟EF CodeFist 实现自己的ORM
    EF+Redis(StackExchange.Redis)实现分布式锁,自测可行
    Sqlite 梳理
    mina.net 梳理
    C# 读取Execl和Access数据库
    MVC4.0网站发布和部署到IIS7.0上的方法
    看懂SqlServer查询计划
    C#数据表加锁解锁
    『C#基础』数据库死锁笔记
  • 原文地址:https://www.cnblogs.com/77-is-here/p/13628406.html
Copyright © 2011-2022 走看看