美文网首页
SAAS-HRM-day11(用户中心)

SAAS-HRM-day11(用户中心)

作者: 程序员Darker | 来源:发表于2019-09-30 08:44 被阅读0次

1. 搭建用户模块中心环境

1.1 后端环境搭建

1.1.1 步骤分析

  1. 创建模块
  2. 导包
  3. 配置
  4. 入口类
  5. 日志
  6. 网关
  7. swagger
  8. 生成代码
  9. 分页插件配置
  10. 测试

1.1.2 步骤实现

  1. 创建模块
  • hrm_parent
    • hrm_user_parent
      • hrm_user_common
      • hrm_user_client
      • hrm_user_service
  1. 导包
  • common
        <!--web场景-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--测试场景-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--公共的工具-->
        <dependency>
            <groupId>cn.wangningbo.hrm</groupId>
            <artifactId>hrm_basic_util</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--不能全部引入mybatis-plus-boot-starter,这是要做数据库操作,这里是不需要的,只需引入核心包解决错误而已-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>2.2.0</version>
        </dependency>
  • client
        <!--引入公共依赖-->
        <dependency>
            <groupId>cn.wangningbo.hrm</groupId>
            <artifactId>hrm_user_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--客户端feign支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  • service
        <!--引入公共依赖-->
        <dependency>
            <groupId>cn.wangningbo.hrm</groupId>
            <artifactId>hrm_user_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- Eureka 客户端依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--引入swagger支持-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!--配置中心支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!--mybatis-plus支持-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <!--数据库支持-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--调用redis-->
        <dependency>
            <groupId>cn.wangningbo.hrm</groupId>
            <artifactId>hrm_basic_redis_client</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--发送短信所需的荣联云通讯的jar//注:这个maven是我手动打的jar包安装成pom依赖-->
        <dependency>
            <groupId>com.cloopen</groupId>
            <artifactId>CCP_REST_SMS_SDK_JAVA</artifactId>
            <version>v2.6.3r</version>
        </dependency>
  1. 配置
server:
  port: 9008
spring:
  application:
    name: hrm-user
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/hrm_user
    username: root
    password: apy06942
mybatis-plus:
  mapper-locations: classpath:cn/itsource/hrm/mapper/*Mapper.xml
  type-aliases-package: cn.wangningbo.hrm.domain,cn.wangningbo.hrm.query
sms:
  account:
    sid: 8a216da86d05dc0b016d33eb2395159a
    token: 2d17dec7382e4c19a8447b47ed830625
    appId: 8a216da86d05dc0b016d33eb23e815a0
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    prefer-ip-address: true
  1. 入口类
package cn.wangningbo.hrm;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@MapperScan("cn.wangningbo.hrm.mapper")
public class User9008Application {
    public static void main(String[] args) {
        SpringApplication.run(User9008Application.class, args);
    }
}
  1. 日志
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
    <!-- 定义日志的根目录 -->
    <property name="LOG_HOME" value="/hrm/" />
    <!-- 定义日志文件名称 -->
    <property name="appName" value="hrm-user"></property>
    <!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <!--
        日志输出格式:
            %d表示日期时间,
            %thread表示线程名,
            %-5level:级别从左显示5个字符宽度
            %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 
            %msg:日志消息,
            %n是换行符
        -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </layout>
    </appender>

    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->  
    <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 指定日志文件的名称
           /hrm/hrm-course/hrm-course.log
        -->
        <file>${LOG_HOME}/${appName}/${appName}.log</file>
        <!--
        当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
        TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
        -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
            滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 
            %i:当文件大小超过maxFileSize时,按照i进行文件滚动
            -->
            <fileNamePattern>${LOG_HOME}/${appName}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <!-- 
            可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
            且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
            那些为了归档而创建的目录也会被删除。
            -->
            <MaxHistory>365</MaxHistory>
            <!-- 
            当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!-- 日志输出格式: -->     
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
        </layout>
    </appender>

    <!-- 
        logger主要用于存放日志对象,也可以定义日志类型、级别
        name:表示匹配的logger类型前缀,也就是包的前半部分
        level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
        additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
        false:表示只用当前logger的appender-ref,true:
        表示当前logger的appender-ref和rootLogger的appender-ref都有效
    -->
    <!-- hibernate logger -->
    <logger name="cn.wangningbo" level="debug" />
    <!-- Spring framework logger -->
    <logger name="org.springframework" level="debug" additivity="false"></logger>



    <!-- 
    root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
    要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 
    -->
    <root level="info">
        <appender-ref ref="stdout" />
        <appender-ref ref="appLogAppender" />
    </root>
</configuration> 
  1. 网关

在网关的配置文件里面配置

zuul:
    routes:
        pageAgent.serviceId: hrm-page-agent # 服务名
        pageAgent.path: /pageAgent/** # 把pageAgent打头的所有请求都转发给hrm-page-agent
  1. swagger

自身配置

package cn.wangningbo.hrm.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("用户中心系统")
                .description("用户中心接口文档说明")
                .termsOfServiceUrl("http://www.wangningbo.cn")
                .contact(new Contact("wangningbo", "", "wang_ning_bo163@163.com"))
                .version("1.0")
                .build();
    }

}

网关配置

resources.add(swaggerResource("用户中心系统", "/services/user/v2/api-docs", "2.0"));
  1. 生成代码

配置文件

#代码放到哪儿
ServiceOutputDir=D:\\Java20190329\\workspace\\java6webSpringCloud\\hrm_parent\\hrm_user_parent\\hrm_user_service\\src\\main\\java
#mapper.xml SQL映射文件目录
ServiceOutputDirXml=D:\\Java20190329\\workspace\\java6webSpringCloud\\hrm_parent\\hrm_user_parent\\hrm_user_service\\src\\main\\resources
#接口路径
CommonOutputDirBase=D:\\Java20190329\\workspace\\java6webSpringCloud\\hrm_parent\\hrm_user_parent\\hrm_user_common\\src\\main\\java
ClientOutputDirBase=D:\\Java20190329\\workspace\\java6webSpringCloud\\hrm_parent\\hrm_user_parent\\hrm_user_client\\src\\main\\java
#设置作者
author=wangningbo
#自定义包路径
parent=cn.wangningbo.hrm

#数据库连接信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///hrm_user
jdbc.user=root
jdbc.pwd=apy06942

生成代码

import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DbType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.*;

/**
 * 新的
 * Created by wangningbo on 2019/08/30
 */
public class GenteratorCode {

    public static void main(String[] args) throws InterruptedException {
        //用来获取Mybatis-Plus.properties文件的配置信息
        ResourceBundle rb = ResourceBundle.getBundle("mybatisplus-user");
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(rb.getString("ServiceOutputDir"));
        gc.setFileOverride(true);
        gc.setActiveRecord(true);// 开启 activeRecord 模式
        gc.setEnableCache(false);// XML 二级缓存
        gc.setBaseResultMap(true);// XML ResultMap
        gc.setBaseColumnList(false);// XML columList
        gc.setAuthor(rb.getString("author"));
        mpg.setGlobalConfig(gc);
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setTypeConvert(new MySqlTypeConvert());
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername(rb.getString("jdbc.user"));
        dsc.setPassword(rb.getString("jdbc.pwd"));
        dsc.setUrl(rb.getString("jdbc.url"));
        mpg.setDataSource(dsc);
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setTablePrefix(new String[] { "t_" });// 此处可以修改为您的表前缀
        strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略
        strategy.setInclude(new String[]{"t_sso","t_vip_address","t_vip_base","t_vip_course_collect",
                "t_vip_course_view","t_vip_grow_log","t_vip_login_log","t_vip_msg","t_vip_realinfo"}); // 需要生成的表
        mpg.setStrategy(strategy);
        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent(rb.getString("parent"));
        pc.setController("web.controller");
        pc.setService("service");
        pc.setServiceImpl("service.impl");
        pc.setEntity("domain");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-rb");
                this.setMap(map);
            }
        };

        List<FileOutConfig> focList = new ArrayList<FileOutConfig>();


        // 调整 xml 生成目录演示
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return rb.getString("ServiceOutputDirXml")+ "/cn/wangningbo/hrm/mapper/" + tableInfo.getEntityName() + "Mapper.xml";
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        // 调整 domain 生成目录演示
        focList.add(new FileOutConfig("/templates/controller.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return rb.getString("ServiceOutputDir")+ "/cn/wangningbo/hrm/web/controller/" + tableInfo.getEntityName() + "Controller.java";
            }
        });
        //=====================接口里面存放==================================//
        // 调整 domain 生成目录演示
        focList.add(new FileOutConfig("/templates/entity.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return rb.getString("CommonOutputDirBase")+ "/cn/wangningbo/hrm/domain/" + tableInfo.getEntityName() + ".java";
            }
        });
        // 调整 query 生成目录演示
        focList.add(new FileOutConfig("/templates/query.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return rb.getString("CommonOutputDirBase")+ "/cn/wangningbo/hrm/query/" + tableInfo.getEntityName() + "Query.java";
            }
        });
        // 调整 client 生成目录演示
        focList.add(new FileOutConfig("/templates/client.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return rb.getString("ClientOutputDirBase")+ "/cn/wangningbo/hrm/client/" + tableInfo.getEntityName() + "Client.java";
            }
        });
        // 调整 ClientHystrixFallbackFactory 生成目录演示
        focList.add(new FileOutConfig("/templates/ClientHystrixFallbackFactory.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return rb.getString("ClientOutputDirBase")+ "/cn/wangningbo/hrm/client/" + tableInfo.getEntityName() + "ClientHystrixFallbackFactory.java";
            }
        });
        //=====================接口里面存放==================================//

        // 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改,
        // 放置自己项目的 src/main/resources/templates 目录下, 默认名称一下可以不配置,也可以自定义模板名称
        TemplateConfig tc = new TemplateConfig();
        tc.setService("/templates/service.java.vm");
        tc.setServiceImpl("/templates/serviceImpl.java.vm");
        tc.setEntity(null);
        tc.setMapper("/templates/mapper.java.vm");
        tc.setController(null);
        tc.setXml(null);
        // 如上任何一个模块如果设置 空 OR Null 将不生成该模块。
        mpg.setTemplate(tc);

        // 执行生成
        mpg.execute();
    }

}
  1. 分页插件配置
package cn.wangningbo.hrm.config;

import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//Spring boot方式:配置分页插件
@EnableTransactionManagement
@Configuration
@MapperScan("cn.wangningbo.hrm.mapper")
public class MybatisPlusConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}
  1. 测试

    postman测试

1.2 前端环境搭建

  1. 创建模块
  2. 拷贝html
  3. 运行
live-server --port=6003
  1. 后端配置跨域放行

在网关那里配置一下

        config.addAllowedOrigin("http://127.0.0.1:6003");
        config.addAllowedOrigin("http://localhost:6003");

完整代码

package cn.wangningbo.hrm.config;

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 GlobalCorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        //1.添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //1) 允许的域,不要写*,否则cookie就无法使用了
        config.addAllowedOrigin("http://127.0.0.1:6001");
        config.addAllowedOrigin("http://localhost:6001");
        config.addAllowedOrigin("http://127.0.0.1:6003");
        config.addAllowedOrigin("http://localhost:6003");
        //2) 是否发送Cookie信息
        config.setAllowCredentials(true);
        //3) 允许的请求方式
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        // 4)允许的头信息
        config.addAllowedHeader("*");
        //2.添加映射路径,我们拦截一切请求
        UrlBasedCorsConfigurationSource configSource = new
                UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
        //3.返回新的CorsFilter.
        return new CorsFilter(configSource);
    }
}

2. 相关技术的实现

2.1 随机数

用于获取验证码等

    public static String getRandomString(int length) {
        String str = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(10);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

2.2 redis存带过期时间的数据

RedisClient新增一个方法

    @PostMapping("/timeout")
    void set(@RequestParam("key")String key, @RequestParam("value")String value,@RequestParam("timeout")int timeout);

RedisClientFallbackFactory那里生成一下,暂时不做处理

            @Override
            public void set(String key, String value, int timeout) {

            }

RedisController

    /**
     * 设置key-value并设置过期时间
     *
     * @param key
     * @param value
     * @param timeout
     */
    @PostMapping("/timeout")
    void set(@RequestParam("key") String key, @RequestParam("value") String value, @RequestParam("timeout") int timeout) {
        //获取连接
        Jedis jedis = RedisUtils.INSTANCE.getSource();
        // 存储key-value,并设置过期时间
        jedis.setex(key, timeout, value);
        //关闭连接
        jedis.close();
    }

2.3 图形验证码

验证码有很多种,我这选择:随机数字+字母

因为这种简单免费,但是有点弱!比较NB的验证码都收费,所以没有选择!

2.3.1 非前后端分离

  1. 后台生成验证码放入session
  2. 后台把验证码写入图片,把图片以流的方式返回给用户
  3. 用户根据图片输入验证码,后台获取到后从seession获取出来做比对.

2.3.2 前后端分离

前后端分离-session不能使用

前端的图片标签<img src="">的src属性,不仅仅可以存放地址,也可以存放base64来显示图片

2.3.2.1 方案说明

html5有两种在浏览器的存放数据机制

  1. localStorage:持久化,不删除一直存在
  2. sessionStorage:前端session

验证码流程:

  1. 用户使用uuid作为验证码的key,并把uuid生成的key存放在localStorage
  2. 前端发送请求,通过key获取验证码
  3. 后端生成6位验证码,存放到redis,key为前端传过来的key,value为生成的6位验证码进行base64加密后的结果,过期时间设置为5分钟。把验证码写入图片,把图片使用base64编码返回
  4. 前端展示后端返回的base64图片验证码
  5. 用户输入验证码,发送请求,把key和用户输入的验证码传递到后端
  6. 后端把用户传入的验证码通过base64加密,后端根据前端传过来的key从redis中获取验证码,比对是否与用户传过来的验证码相同。

2.3.2.1 方案实现

  1. 前端
        methods: {
            //构造请求,获取验证码
            getValidateCode() {
                //1 构造uuid
                var codeUuid = localStorage.getItem("codeUuid");
                let uuid = null;
                if (codeUuid) {
                    uuid = codeUuid;
                } else {
                    uuid = this.uuid();
                    localStorage.setItem("codeUuid", uuid);
                }

                //2 获取验证码
                this.$http.get("/user/imgCode?uuid=" + uuid)
                    .then(result => {
                        this.base64Code = result.data;
                    });
                ;
            },
            // 构造前端的uuid
            uuid() {
                return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                    var r = Math.random() * 16 | 0,
                        v = c == 'x' ? r : (r & 0x3 | 0x8);
                    return v.toString(16);
                });
            }
        },
        mounted() {
            //初始化验证码
            this.getValidateCode();
        }
  1. 后端的controller
package cn.wangningbo.hrm.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 图形验证码
 */
@RestController
@RequestMapping("/imgCode")
public class ImageValidateCodeController {

    @Autowired
    private ImageValidateCodeService service;

    // 获取图片验证码
    @GetMapping
    public String getCode(String uuid) {
        return service.getCode(uuid);
    }
}
  1. IImageValidateCodeService
package cn.wangningbo.hrm.service;

public interface IImageValidateCodeService{
    String getCode(String uuid);
}
  1. ImageValidateCodeImpl
package cn.wangningbo.hrm.service.impl;

import cn.wangningbo.hrm.client.RedisClient;
import cn.wangningbo.hrm.service.IImageValidateCodeService;
import cn.wangningbo.hrm.util.VerifyCodeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import sun.misc.BASE64Encoder;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

@Service
public class ImageValidateCodeImpl implements IImageValidateCodeService {
    @Autowired
    private RedisClient redisClient;

    @Override
    public String getCode(String uuid) {
        // 生成6位验证码,并将所有英文字母转换为小写字母
        String code = VerifyCodeUtils.generateVerifyCode(6).toLowerCase();
        // 把验证码存放到redis,key使用前端传过来的uuid,并设置过期时间为5分钟
        redisClient.set(uuid, code, 300);
        // 输出到图片
        ByteArrayOutputStream data = new ByteArrayOutputStream();
        try {
            // 设置图片的长度,宽度,图片显示的内容
            VerifyCodeUtils.outputImage(100, 30, data, code);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 把图片加密返回
        return new BASE64Encoder().encode(data.toByteArray());
    }
}
  1. 刷新前端,即可看到验证码已出现!

2.4 短信验证码

  1. 导包(已经导入了,自己maven安装的那个)
  2. 发送短信的工具
package cn.wangningbo.hrm.util;

import com.cloopen.rest.sdk.CCPRestSmsSDK;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Set;

@Component
@ConfigurationProperties(prefix = "sms.account")
public class SmsHelper {

    private String sid;
    private String token;
    private String appId;

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public void sendSms(String phones,String templateId ,String[] params){
        System.out.println(sid);
        System.out.println(token);
        System.out.println(appId);
        HashMap<String, Object> result = null;
        CCPRestSmsSDK restAPI = new CCPRestSmsSDK();
        restAPI.init("app.cloopen.com", "8883");// 初始化服务器地址和端口,格式如下,服务器地址不需要写https://
        restAPI.setAccount(sid,token);// 初始化主帐号和主帐号TOKEN
        restAPI.setAppId(appId);// 初始化应用ID
        result = restAPI.sendTemplateSMS(phones,templateId ,params);
        System.out.println("SDKTestSendTemplateSMS result=" + result);

        if("000000".equals(result.get("statusCode"))){
            //正常返回输出data包体信息(map)
            HashMap<String,Object> data = (HashMap<String, Object>) result.get("data");
            Set<String> keySet = data.keySet();
            for(String key:keySet){
                Object object = data.get(key);
                System.out.println(key +" = "+object);
            }
        }else{
            //异常返回输出错误码和错误信息
            System.out.println("错误码=" + result.get("statusCode") +" 错误信息= "+result.get("statusMsg"));
        }
    }
}
  1. 测试
package cn.wangningbo.hrm.util;


import cn.wangningbo.hrm.User9008Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = User9008Application.class)
public class SmsHelperTest {

    @Autowired
    private SmsHelper smsHelper;

    @Test
    public void sendSms() {
        smsHelper.sendSms("17752526745","1",new String[]{"8888","5"});
    }
}

相关文章

  • SAAS-HRM-day11(用户中心)

    1. 搭建用户模块中心环境1.1 后端环境搭建1.1.1 步骤分析1.1.2 步骤实现1.2 前端环境搭建 2. ...

  • 用户中心

    layout: "post"title: "用户中心"date: "2018-04-11 18:12" 用户中心 ...

  • 用户中心

    路由,跳转登录页,填写登录信息(用户名(昵称,手机,邮箱),密码,验证码),

  • 用户中心?

    自从交互设计,用户体验被人们所关注,以人为中心,以用户为中心的概念就被泛滥的传开了,以至于让我们感觉,以前做的产品...

  • 用户中心

    经过几天的设计,用户中心(UC)v1已经成型。通过V1,可以减少原来很多表,同时也减少关联,而且基本上都在系统表中...

  • 4. 秒杀购物商城基础服务-用户中心

    基础服务-用户中心 什么是用户中心? 用户中心,在我们的概念里面范围比较的广泛,包含了用户信息、账号信息以及租户信...

  • 产品经理怎样做用户研究

    产品狗总把“以用户为中心”挂在嘴边。既然要以“用户为中心”,我们就要更好地了解用户。了解用户,常用的办法就是用户研...

  • 《用户体验要素:以用户为中心的产品设计》阅读笔记

    用户体验要素:以用户为中心的产品设计 1 book info 1.1 《用户体验要素:以用户为中心的产品设计》翻译...

  • 用户故事与敏捷方法之五---用户角色建模

    敏捷模式下,是以用户为中心的设计。 如何做到以用户为中心,要从用户角色建模开始。 一、用户角色建模 软件客户和最终...

  • 我是个喜欢“被动”的人,现在被搞得越来越“主动”

    A用户:你们用户体验设计师是做什么的 我:以用户为中心的设计 A用户:怎么做到以用户为中心的设计 我:方法很多啦,...

网友评论

      本文标题:SAAS-HRM-day11(用户中心)

      本文链接:https://www.haomeiwen.com/subject/tnlcpctx.html