尚筹网09用户注册

总体思路

创建数据库表

create table t_member(
   id                   int(11) not null auto_increment,
   loginacct            varchar(255) not null,
   userpswd             char(200) not null,
   username             varchar(255),
   email                varchar(255),
   authstatus           tinyint(4) comment '实名认证状态 0 - 未实名认证, 1 - 实名认证申请中, 2 - 已实名认证',
   usertype             tinyint(4) comment ' 0 - 个人, 1 - 企业',
   realname             varchar(255),
   cardnum              varchar(255),
   accttype             tinyint(4) comment '0 - 企业, 1 - 个体, 2 - 个人, 3 - 政府',
   primary key (id));

api接口调用微服务service

发送验证码

目标

1、将验证码发送到用户手机上

2、将验证码存入redis

思路

准备短信发送API

导入依赖

<!--ali短信-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.15</version>
</dependency>
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-util</artifactId>
    <version>9.3.7.v20160115</version>
</dependency>

加入HttpUtil

依赖

<!--阿里短信-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.15</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.2.1</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.2.1</version>
</dependency>
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-util</artifactId>
    <version>9.3.7.v20160115</version>
</dependency>

代码

package com.aliyun.api.gateway.demo.util;
public class HttpUtils {

    /**
     * get
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @return
     * @throws Exception
     */
    public static HttpResponse doGet(String host, String path, String method,
                                     Map<String, String> headers,
                                     Map<String, String> querys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpGet request = new HttpGet(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        return httpClient.execute(request);
    }

    /**
     * post form
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param bodys
     * @return
     * @throws Exception
     */
    public static HttpResponse doPost(String host, String path, String method,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      Map<String, String> bodys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (bodys != null) {
            List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();

            for (String key : bodys.keySet()) {
                nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));
            }
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
            formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
            request.setEntity(formEntity);
        }

        return httpClient.execute(request);
    }

    /**
     * Post String
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPost(String host, String path, String method,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      String body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (StringUtils.isNotBlank(body)) {
            request.setEntity(new StringEntity(body, "utf-8"));
        }

        return httpClient.execute(request);
    }

    /**
     * Post stream
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPost(String host, String path, String method,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      byte[] body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (body != null) {
            request.setEntity(new ByteArrayEntity(body));
        }

        return httpClient.execute(request);
    }

    /**
     * Put String
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPut(String host, String path, String method,
                                     Map<String, String> headers,
                                     Map<String, String> querys,
                                     String body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPut request = new HttpPut(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (StringUtils.isNotBlank(body)) {
            request.setEntity(new StringEntity(body, "utf-8"));
        }

        return httpClient.execute(request);
    }

    /**
     * Put stream
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPut(String host, String path, String method,
                                     Map<String, String> headers,
                                     Map<String, String> querys,
                                     byte[] body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPut request = new HttpPut(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (body != null) {
            request.setEntity(new ByteArrayEntity(body));
        }

        return httpClient.execute(request);
    }

    /**
     * Delete
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @return
     * @throws Exception
     */
    public static HttpResponse doDelete(String host, String path, String method,
                                        Map<String, String> headers,
                                        Map<String, String> querys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpDelete request = new HttpDelete(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        return httpClient.execute(request);
    }

    private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
        StringBuilder sbUrl = new StringBuilder();
        sbUrl.append(host);
        if (!StringUtils.isBlank(path)) {
            sbUrl.append(path);
        }
        if (null != querys) {
            StringBuilder sbQuery = new StringBuilder();
            for (Map.Entry<String, String> query : querys.entrySet()) {
                if (0 < sbQuery.length()) {
                    sbQuery.append("&");
                }
                if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
                    sbQuery.append(query.getValue());
                }
                if (!StringUtils.isBlank(query.getKey())) {
                    sbQuery.append(query.getKey());
                    if (!StringUtils.isBlank(query.getValue())) {
                        sbQuery.append("=");
                        sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
                    }
                }
            }
            if (0 < sbQuery.length()) {
                sbUrl.append("?").append(sbQuery);
            }
        }

        return sbUrl.toString();
    }

    private static HttpClient wrapClient(String host) {
        HttpClient httpClient = new DefaultHttpClient();
        if (host.startsWith("https://")) {
            sslClient(httpClient);
        }

        return httpClient;
    }

    private static void sslClient(HttpClient httpClient) {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String str) {

                }

                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String str) {

                }
            };
            ctx.init(null, new TrustManager[]{tm}, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = httpClient.getConnectionManager();
            SchemeRegistry registry = ccm.getSchemeRegistry();
            registry.register(new Scheme("https", 443, ssf));
        } catch (KeyManagementException ex) {
            throw new RuntimeException(ex);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException(ex);
        }
    }
}

创建工具方法

/**
     * @param host     短信接口调用url地址
     * @param path     具体发送短信地址
     * @param method   请求方法
     * @param phoneNum 手机号
     * @param appCode  应用码
     * @param sign
     * @param skin
     * @return 成功返回验证码
     */
    public static ResultEntity<String> sendCodeByShortMessage(
            String host,
            String path,
            String method,
            String phoneNum,
            String appCode,
            String sign,
            String skin) {

        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appCode);
        Map<String, String> querys = new HashMap<String, String>();
//        验证码
        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i < 4; i++) {
            int random = (int) (Math.random() * 10);
            stringBuilder.append(random);
        }
        String code = stringBuilder.toString();
        querys.put("param", code);
        querys.put("phone", phoneNum);
        querys.put("sign", sign);
        querys.put("skin", skin);
        //JDK 1.8示例代码请在这里下载:  http://code.fegine.com/Tools.zip

        try {
            /**
             * 重要提示如下:
             * HttpUtils请从
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
             * 或者直接下载:
             * http://code.fegine.com/HttpUtils.zip
             * 下载
             *
             * 相应的依赖请参照
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
             * 相关jar包(非pom)直接下载:
             * http://code.fegine.com/aliyun-jar.zip
             */
            HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);
            //System.out.println(response.toString());如不输出json, 请打开这行代码,打印调试头部状态码。
            //状态码: 200 正常;400 URL无效;401 appCode错误; 403 次数用完; 500 API网管错误
            StatusLine statusLine = response.getStatusLine();
            int statusCode = statusLine.getStatusCode();
            String reasonPhrase = statusLine.getReasonPhrase();

            if (statusCode == 200) {
                return ResultEntity.sucessWithData(code);
            }
            return ResultEntity.failed(reasonPhrase);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failed(e.getMessage());
        }

    }

yml配置文件读取数据

导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

编写配置文件

编写短信property

package com.adom.authentication.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;


@Component
@ConfigurationProperties(prefix = "short.message")
public class ShortMessageProperties {
    // 调用短信发送接口时的访问地址
    private String host;
    // 具体访问路径
    private String path;
    // 请求方式
    private String method;
    // 登录阿里云后,进入管理控制台->云市场->已购买服务,复制AppCode
    private String appCode;
    // 签名编号
    private String sign;
    // 模板编号
    private String skin;

    public ShortMessageProperties() {
    }

    public ShortMessageProperties(String host, String path, String method, String appCode, String sign, String skin) {
        this.host = host;
        this.path = path;
        this.method = method;
        this.appCode = appCode;
        this.sign = sign;
        this.skin = skin;
    }

前端思路(忽略)

后端代码

创建发送短信验证码的controller

1、先发送短信,若发送成功,则把验证码加入到redis

@ResponseBody
@RequestMapping(value = "/auth/member/send/short/message.json", method = RequestMethod.POST)
public ResultEntity<String> sendMessage(@RequestParam("phoneNum") String phoneNum) {
    // 1.发送验证码到手机
    ResultEntity<String> sendMeassageResultEntity = CrowdUtil.sendCodeByShortMessage(
            shortMessageProperties.getHost(),
            shortMessageProperties.getPath(),
            shortMessageProperties.getMethod(), phoneNum,
            shortMessageProperties.getAppCode(),
            shortMessageProperties.getSign(),
            shortMessageProperties.getSkin());
    // 2,判断短信发送的结果
    if (ResultEntity.SUCCESS.equals(sendMeassageResultEntity.getResult())) {
        // 3.如果发送成功,则将验证码存入redis
        String code = sendMeassageResultEntity.getData();
        String key = ConstantUtil.REDIS_CODE_PREFIX + phoneNum;
        ResultEntity<String> saveCodeResultEntity = redisRemoteService.setRedisKeyValueRemoteWithTimeout(key, code, 15, TimeUnit.MINUTES);
        if (ResultEntity.SUCCESS.equals(saveCodeResultEntity.getResult())) {
            return ResultEntity.successWithoutData();
        } else {
            return saveCodeResultEntity;
        }
    } else {
        return sendMeassageResultEntity;
    }
}

redis中保存验证码数据的key

声明redis-provider功能api

@FeignClient("adom-crowd-redis")
public interface RedisRemoteService {


    @RequestMapping("/set/redis/key/value/remote")
    ResultEntity<String> setRedisKeyValueRemote(
            @RequestParam("key") String key, @RequestParam("value") String value);

    @RequestMapping("/set/redis/key/value/remote/with/timeout")
    ResultEntity<String> setRedisKeyValueRemoteWithTimeout(
            @RequestParam("key") String key, @RequestParam("value") String value, @RequestParam("time") long time, @RequestParam("timeUnix") TimeUnit timeUnit);

    @RequestMapping("/get/redis/string/value/by/key")
    ResultEntity<String> getRedisStringValueByKeyRemote(@RequestParam("key") String key);

    @RequestMapping("/remove/redis/key/remote")
    ResultEntity<String> removeRedisKeyRemote(@RequestParam("key") String key);
}

Redis-provider功能实现

@RestController
public class RedisController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @RequestMapping("set/redis/key/value/remote")
    ResultEntity<String> setRedisKeyValueRemote(
            @RequestParam("key") String key,
            @RequestParam("value")String value){
        try {
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            operations.set(key,value);
            return ResultEntity.successWithoutData();
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failed(e.getMessage());
        }
    }
    @RequestMapping("set/redis/key/value/remote/with/timeout")
    ResultEntity<String> setRedisKeyValueRemoteWithTimeout(
            @RequestParam("key") String key,
            @RequestParam("value")String value,
            @RequestParam("time") long time,
            @RequestParam("timeUnit") TimeUnit timeUnit){
        try {
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            operations.set(key,value,time,timeUnit);
            return ResultEntity.successWithoutData();
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failed(e.getMessage());
        }
    }
    @RequestMapping("get/redis/string/value/by/key")
    ResultEntity<String> getRedisStringValueByKey(@RequestParam("key") String key){
        try {
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            String value = operations.get(key);
            return ResultEntity.sucessWithData(value);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failed(e.getMessage());
        }
    }

    @RequestMapping("remove/redis/key/remote")
    ResultEntity<String> removeRedisKeyRemote(@RequestParam("key") String key){
        try {
            redisTemplate.delete(key);
            return ResultEntity.successWithoutData();
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failed(e.getMessage());
        }
    }

}

代码缺陷(未解决)

分布式事务

举例

发送短信操作和redis保存操作在执行时都有可能失败.如果发生其中一个操作失败,另一个成功,那么数据整体就会发生不一致的情况.

分析

如果是在以前关系型数据库的事务操作中,可以采用回滚机制,一个事物多个操作中有任何

一个失败,则整个事务全部回滚.

在分布式环境下,没办法将多个具体操作纳入到一个统一的事务中,一起提交、一起回滚.

也不能使用逆操作手动撤销,因为逆操作除了功能和原本操作不同,其他方面和原本的操作性质是一样的.

解决方法

yml配置文件读取数据

加入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

yml配置

这些配置项全部都是自定义的,完全没有框架的支持.

short:
  message:
    app-code: 303208760dc14fb994c6dfba5c82e1e6
    host: https://feginesms.market.alicloudapi.com
    method: GET
    path: /codeNotice
    sign: 1
    skin: 1

java类中引用方式

@Component
@ConfigurationProperties(prefix = "short.message")
public class ShortMessageProperties {

意义:以后在SpringBoot环境下开发时,如果某些信息不能在java代码中写死,就可以使用这样的机制在yml配置文件中配置,再使用@value注解读取.ymlproperties文件都可以.

执行注册

流程分析

目标

如果针对注册操作所做的各项验证能够通过,则将Member信息存入数据库.

思路

1、接受表单数据
    a)登陆账号
    b)密码
    c)手机号
    d)验证码
2、检查验证码是否有效
    a)无效:返回失败信息,停止执行
    b)有效继续执行
3、检查手机号是否有效
    a)无效:返回失败信息,停止执行
    b)有效:继续执行
4、拼接接收到验证码的key
5、调用redis-provider的api方法获取对应的验证码值
    a)没有查询到值:返回失败信息,停止执行
    b)查询到有效值:继续执行
6、进行比较
    a)表单提交的验证码
    b)redis取回的验证码
7、不一致:返回失败信息,停止执行
8、一致
a)从redis中删除当前key对应的验证码
b)继续执行
9、调用数据库api方法检查登陆账号是否被占用
a)已经被占用:返回失败信息,停止执行
b)没有被占用:继续执行
10、密码加密
11、调用数据库api方法检查登陆账号是否被占用

封装MemberVO

public class MemberVO {
 private String loginAcct;
    private String userPswd;
    private String email;
    private String userName;
    private String phoneNum;
    private String code;

    public MemberVO() {
    }

    public MemberVO(String loginAcct, String userPswd, String email, String userName, String phoneNum, String code) {
        this.loginAcct = loginAcct;
        this.userPswd = userPswd;
        this.email = email;
        this.userName = userName;
        this.phoneNum = phoneNum;
        this.code = code;
    }

调用数据库providerapi

@RequestMapping("/save/member/remote")
public ResultEntity<String> saveMember(@RequestBody MemberPO memberPO);

数据库provider

数据库保存

Controller

@RequestMapping("/save/member/remote")
public ResultEntity<String> saveMember(@RequestBody MemberPO memberPO) {

    try {
        memberService.saveMember(memberPO);
        return ResultEntity.successWithoutData();
    } catch (Exception e) {
        if (e instanceof DuplicateKeyException) {
            return ResultEntity.failed(ConstantUtil.MESSAGE_LOGIN_ACCT_ALREADY_IN);
        }
        return ResultEntity.failed(e.getMessage());
    }
}

Service

@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class, readOnly = false)
public void saveMember(MemberPO memberPO) {
    memberPOMapper.insertSelective(memberPO);
}

Mapper

int insertSelective(MemberPO record);

Sql

<insert id="insertSelective" parameterType="com.example.entity.po.MemberPO" >
  insert into t_member
  <trim prefix="(" suffix=")" suffixOverrides="," >
    <if test="id != null" >
      id,
    </if>
    <if test="loginAcct != null" >
      login_acct,
    </if>
    <if test="userPswd != null" >
      user_pswd,
    </if>
    <if test="userName != null" >
      user_name,
    </if>
    <if test="email != null" >
      email,
    </if>
    <if test="authStatus != null" >
      auth_status,
    </if>
    <if test="userType != null" >
      user_type,
    </if>
    <if test="realName != null" >
      real_name,
    </if>
    <if test="cardNum != null" >
      card_num,
    </if>
    <if test="acctType != null" >
      acct_type,
    </if>
  </trim>
  <trim prefix="values (" suffix=")" suffixOverrides="," >
    <if test="id != null" >
      #{id,jdbcType=INTEGER},
    </if>
    <if test="loginAcct != null" >
      #{loginAcct,jdbcType=VARCHAR},
    </if>
    <if test="userPswd != null" >
      #{userPswd,jdbcType=CHAR},
    </if>
    <if test="userName != null" >
      #{userName,jdbcType=VARCHAR},
    </if>
    <if test="email != null" >
      #{email,jdbcType=VARCHAR},
    </if>
    <if test="authStatus != null" >
      #{authStatus,jdbcType=INTEGER},
    </if>
    <if test="userType != null" >
      #{userType,jdbcType=INTEGER},
    </if>
    <if test="realName != null" >
      #{realName,jdbcType=VARCHAR},
    </if>
    <if test="cardNum != null" >
      #{cardNum,jdbcType=VARCHAR},
    </if>
    <if test="acctType != null" >
      #{acctType,jdbcType=INTEGER},
    </if>
  </trim>
</insert>

执行注册

controller

@RequestMapping("/auth/do/member/register")
public String register(MemberVO memberVO, ModelMap modelMap) {
    // 1.获取用户输入的手机号
    String phoneNum = memberVO.getPhoneNum();
    // 2.拼redis中存储验证码的key
    String key = ConstantUtil.REDIS_CODE_PREFIX + phoneNum;
    // 3.从redis读取key对应的value
    ResultEntity<String> resultEntity = redisRemoteService.getRedisStringValueByKeyRemote(key);
    // 4.查询操作是否有效
    String result = resultEntity.getResult();
    if (ResultEntity.FAILED.equals(result)) {
        modelMap.addAttribute(ConstantUtil.ATTR_NANE_MESSAGE, resultEntity.getMessage());
        return "member-reg";
    }
    String redisCode = resultEntity.getData();
    if (redisCode == null) {
        modelMap.addAttribute(ConstantUtil.ATTR_NANE_MESSAGE, ConstantUtil.MESSAGE_CODE_NOT_EXISTS);
        return "member-reg";
    }
    // 5.如果能够到value则比较表单的验证码和redis的验证码
    String formCode = memberVO.getCode();
    if (!Objects.equals(formCode, redisCode)) {
        modelMap.addAttribute(ConstantUtil.ATTR_NANE_MESSAGE, ConstantUtil.MESSAGE_CODE_INVALID);
        return "member-reg";
    }
    // 6.如果验证码一致,则从redis删除
    redisRemoteService.removeRedisKeyRemote(key);
    // 7.执行密码加密
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    String userpswd = memberVO.getUserPswd();
    String encode = passwordEncoder.encode(userpswd);
    memberVO.setUserPswd(encode);
    // 8.执行保存
    // 创建空的MemberPO对象
    MemberPO memberPO = new MemberPO();
    // 复制属性
    BeanUtils.copyProperties(memberVO, memberPO);
    // 调用远程方法
    ResultEntity<String> saveMemberResultEntity = mySQLRemoteService.saveMember(memberPO);
    if (ResultEntity.FAILED.equals(saveMemberResultEntity)) {
        modelMap.addAttribute(ConstantUtil.ATTR_NANE_MESSAGE, saveMemberResultEntity.getMessage());
        return "member-reg";
    }
    return "redirect:/auth/member/to/login/page";
}

一些问题

SpringBoot注入失败的原因有哪些

SpringIOC找不到Bean对象

1、没有开启扫描的包

2、没有注入Bean对象

3、没有添加组件注解

4、方法没有@Bean修饰

@FeignClients需要加入扫描哪些包才可以找到bean对象

 

mybatis之 trim prefix="(" suffix=")"

trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefixsuffix;可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverridessuffixOverrides;正因为trim有这样的功能,所以我们也可以非常简单的利用trim来代替where元素的功能。

1.<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>

prefix:trim标签内sql语句加上前缀。

suffix:trim标签内sql语句加上后缀。

suffixOverrides:指定去除多余的后缀内容,如:suffixOverrides=",",去除trim标签内sql语句多余的后缀","

prefixOverrides:指定去除多余的前缀内容

suffixOverrides=","

执行的sql语句也许是这样的:insert into cart (id,user_id,deal_id,) values(1,2,1,);显然是错误的

指定之后语句就会变成insert into cart (id,user_id,deal_id) values(1,2,1);这样就将去掉了。

前缀同理。

获取上述短信接口的appcode

阿里云-》云市场-API-》电子商务找到如下:

购买成功后

原文地址:https://www.cnblogs.com/Adam-Ye/p/13376586.html