淘东电商项目(26) -门户登录功能

引言

本文代码已提交至Github(版本号:8f3a993f0f9b92071437d16ed290e27ac1c64cde),有兴趣的同学可以下载来看看:https://github.com/ylw-github/taodong-shop

在上一节《淘东电商项目(25) -门户注册功能》,主要讲解了注册的整个流程(前端+后台)。

本文主要讲解前端与后台交互部分,实现登录的整个流程(前端+后端)。

本文目录结构:
l____引言
l____ 1. 登录
l________ 1.1 前端代码
l________ 1.2 后端代码
l____ 2. 登录成功主页面显示
l________ 2.1 前端代码
l________ 2.2 后端代码
l____ 3. 测试
l____总结

1. 登录

1.1 前端代码

1.前端界面:
在这里插入图片描述
2.界面HTML代码:

<div class="layui-fulid" id="house-login">
    <form action="login" method="post">
        <div class="layui-form">
            <p>手机号登录</p>

            <div class="layui-input-block login">
                <i class="layui-icon layui-icon-username"></i> <input type="text"
                                                                      required lay-verify="required" name="mobile"
                                                                      value="${(loginVo.mobile)!''}"
                                                                      placeholder="请输入手机号码"
                                                                      class="layui-input">
            </div>

            <div class="layui-input-block login">
                <i class="layui-icon layui-icon-vercode"></i> <input
                        type="password" required lay-verify="required" name="password"
                        value="${(loginVo.password)!''}" placeholder="请输入密码"
                        class="layui-input">
            </div>

            <div class="layui-input-block getCode">
                <input type="text" name="graphicCode" required lay-verify="required"
                       placeholder="请输入验证码" class="layui-input"> <img alt=""
                                                                      src="getVerify" onclick="getVerify(this);"
                                                                      style="border: 1px solid #e2e2e2;font-size: 18px;height: 48px;margin-top: -93px;width: 44%;background-color: #e8d6c0;margin-left: 166px;">
            </div>
            <span
                    style="color: red; font-size: 20px; font-weight: bold; font-family: '楷体', '楷体_GB2312';">${error!''}</span>
            <button class="layui-btn" style="margin-top: 5px;" lay-submit lay-filter="user-login">登录</button>
        </div>
    </form>
</div>

1.2 后端代码

1.登录VO实体类:

@Data
public class LoginVo {

	/**
	 * 手机号码
	 */
	@NotBlank(message = "手机号码不能为空")
	@Size(min = 11, max = 11, message = "手机号码长度不正确")
	@Pattern(regexp = "^(((13[0-9])|(14[579])|(15([0-3]|[5-9]))|(16[6])|(17[0135678])|(18[0-9])|(19[89]))\\d{8})$", message = "手机号格式错误")
	private String mobile;
	/**
	 * 密码
	 */
	@NotNull(message = "密码不能为空!")
	private String password;

	/**
	 * 验证码
	 */
	@NotNull(message = "密码不能为空!")
	private String graphicCode;

}

2.Cookie工具类:

/**
 * description: Cookie工具类
 * create by: YangLinWei
 * create time: 2020/3/10 5:27 下午
 */
public final class CookieUtils {

	/**
	 * 得到Cookie的值, 不编码
	 * 
	 * @param request
	 * @param cookieName
	 * @return
	 */
	public static String getCookieValue(HttpServletRequest request, String cookieName) {
		return getCookieValue(request, cookieName, false);
	}

	/**
	 * 得到Cookie的值,
	 * 
	 * @param request
	 * @param cookieName
	 * @return
	 */
	public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
		Cookie[] cookieList = request.getCookies();
		if (cookieList == null || cookieName == null) {
			return null;
		}
		String retValue = null;
		try {
			for (int i = 0; i < cookieList.length; i++) {
				if (cookieList[i].getName().equals(cookieName)) {
					if (isDecoder) {
						retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
					} else {
						retValue = cookieList[i].getValue();
					}
					break;
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return retValue;
	}

	/**
	 * 得到Cookie的值,
	 * 
	 * @param request
	 * @param cookieName
	 * @return
	 */
	public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
		Cookie[] cookieList = request.getCookies();
		if (cookieList == null || cookieName == null) {
			return null;
		}
		String retValue = null;
		try {
			for (int i = 0; i < cookieList.length; i++) {
				if (cookieList[i].getName().equals(cookieName)) {
					retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
					break;
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return retValue;
	}

	/**
	 * 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue) {
		setCookie(request, response, cookieName, cookieValue, -1);
	}

	/**
	 * 设置Cookie的值 在指定时间内生效,但不编码
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage) {
		setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
	}

	/**
	 * 设置Cookie的值 不设置生效时间,但编码
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, boolean isEncode) {
		setCookie(request, response, cookieName, cookieValue, -1, isEncode);
	}

	/**
	 * 设置Cookie的值 在指定时间内生效, 编码参数
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage, boolean isEncode) {
		doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
	}

	/**
	 * 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage, String encodeString) {
		doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
	}

	/**
	 * 删除Cookie带cookie域名
	 */
	public static void deleteCookie(HttpServletRequest request, HttpServletResponse response, String cookieName) {
		doSetCookie(request, response, cookieName, "", -1, false);
	}

	/**
	 * 设置Cookie的值,并使其在指定时间内生效
	 * 
	 * @param cookieMaxage
	 *            cookie生效的最大秒数
	 */
	private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage, boolean isEncode) {
		try {
			if (cookieValue == null) {
				cookieValue = "";
			} else if (isEncode) {
				cookieValue = URLEncoder.encode(cookieValue, "utf-8");
			}
			Cookie cookie = new Cookie(cookieName, cookieValue);
			if (cookieMaxage > 0)
				cookie.setMaxAge(cookieMaxage);
			if (null != request) {// 设置域名的cookie
				String domainName = getDomainName(request);
				System.out.println(domainName);
				if (!"localhost".equals(domainName)) {
					// cookie.setDomain(domainName);
				}
			}
			cookie.setPath("/");
			response.addCookie(cookie);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 设置Cookie的值,并使其在指定时间内生效
	 * 
	 * @param cookieMaxage
	 *            cookie生效的最大秒数
	 */
	private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage, String encodeString) {
		try {
			if (cookieValue == null) {
				cookieValue = "";
			} else {
				cookieValue = URLEncoder.encode(cookieValue, encodeString);
			}
			Cookie cookie = new Cookie(cookieName, cookieValue);
			if (cookieMaxage > 0)
				cookie.setMaxAge(cookieMaxage);
			if (null != request) {// 设置域名的cookie
				String domainName = getDomainName(request);
				System.out.println(domainName);
				if (!"localhost".equals(domainName)) {
					// 本地测试的时候不要写.实际发布时在打开
					// cookie.setDomain(domainName);
				}
			}
			cookie.setPath("/");
			response.addCookie(cookie);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 得到cookie的域名
	 */
	private static final String getDomainName(HttpServletRequest request) {
		String domainName = null;

		String serverName = request.getRequestURL().toString();
		if (serverName == null || serverName.equals("")) {
			domainName = "";
		} else {
			final int end = serverName.lastIndexOf("/");
			serverName = serverName.substring(0, end);
			final String[] domains = serverName.split("\\.");
			int len = domains.length;
			if (len > 3) {
				// www.xxx.com.cn
				domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
			} else if (len <= 3 && len > 1) {
				// xxx.com or xxx.cn
				domainName = "." + domains[len - 2] + "." + domains[len - 1];
			} else {
				domainName = serverName;
			}
		}

		if (domainName != null && domainName.indexOf(":") > 0) {
			String[] ary = domainName.split("\\:");
			domainName = ary[0];
		}
		return domainName;
	}

}

3.登录Controller:

/**
 * description: 登录页
 * create by: YangLinWei
 * create time: 2020/3/5 1:48 下午
 */
@Controller
public class LoginController extends BaseWebController {
    /**
     * 跳转到登陆页面页面
     */
    private static final String MB_LOGIN_FTL = "member/login";

    @Autowired
    private MemberLoginServiceFeign memberLoginServiceFeign;
    /**
     * 重定向到首页
     */
    private static final String REDIRECT_INDEX = "redirect:/";

    /**
     * 跳转页面
     *
     * @return
     */
    @GetMapping("/login")
    public String getLogin() {
        return MB_LOGIN_FTL;
    }

    /**
     * 接受请求参数
     *
     * @return
     */
    @PostMapping("/login")
    public String postLogin(@ModelAttribute("loginVo") @Validated LoginVo loginVo,
							BindingResult bindingResult, Model model, HttpServletRequest request,
                            HttpServletResponse response, HttpSession httpSession) {

        if (bindingResult.hasErrors()) {
            // 如果参数有错误的话
            // 获取第一个错误!
            String errorMsg = bindingResult.getFieldError().getDefaultMessage();
            setErrorMsg(model, errorMsg);
            return MB_LOGIN_FTL;
        }

        // 1.图形验证码判断
        String graphicCode = loginVo.getGraphicCode();
        if (!RandomValidateCodeUtil.checkVerify(graphicCode, httpSession)) {
            setErrorMsg(model, "图形验证码不正确!");
            return MB_LOGIN_FTL;
        }

        // 2.将vo转换dto调用会员登陆接口
        UserLoginInDTO userLoginInpDTO = WebBeanUtils.voToDto(loginVo, UserLoginInDTO.class);
        userLoginInpDTO.setLoginType(Constants.MEMBER_LOGIN_TYPE_PC);
        String info = webBrowserInfo(request);
        userLoginInpDTO.setDeviceInfor(info);
        BaseResponse<JSONObject> login = memberLoginServiceFeign.login(userLoginInpDTO);
        if (!isSuccess(login)) {
            setErrorMsg(model, login.getMsg());
            return MB_LOGIN_FTL;
        }
        // 3.登陆成功之后如何处理 保持会话信息 将token存入到cookie 里面 首页读取cookietoken 查询用户信息返回到页面展示
        JSONObject data = login.getData();
        String token = data.getString("token");
        CookieUtils.setCookie(request, response, WebConstants.LOGIN_TOKEN_COOKIENAME, token);
        return REDIRECT_INDEX;
    }

}

2. 登录成功主页面显示

2.1 前端代码

修改head.ftl(代码片段):

<span class="layui-breadcrumb" lay-separator="|">
      <#if desensMobile??>
          <a href="">${desensMobile}</a>
          <a href="">我的订单</a>
          <a href="/exit">退出</a>
      <#else >
          <a href="login">登录</a>
      </#if>
   <a href="">我的订单</a>
   <a href="">在线客服</a>
 </span>

2.2 后端代码

直接贴上Controller代码:

@Controller
public class IndexController extends BaseWebController {

    @Autowired
    private MemberServiceFeign memberServiceFeign;
    /**
     * 跳转到index页面
     */
    private static final String INDEX_FTL = "index";

    @RequestMapping("/")
    public String index(HttpServletRequest request, HttpServletResponse response, Model model) {
        // 1.从cookie 中 获取 会员token
        String token = CookieUtils.getCookieValue(request, WebConstants.LOGIN_TOKEN_COOKIENAME, true);
        if (!StringUtils.isEmpty(token)) {
            // 2.调用会员服务接口,查询会员用户信息
            BaseResponse<UserOutDTO> userInfo = memberServiceFeign.getInfo(token);
            if (isSuccess(userInfo)) {
                UserOutDTO data = userInfo.getData();
                if (data != null) {
                    String mobile = data.getMobile();
                    // 对手机号码实现脱敏
                    String desensMobile = mobile.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
                    model.addAttribute("desensMobile", desensMobile);
                }

            }

        }
        return INDEX_FTL;
    }
}

3. 测试

当前数据库已经注册的用户如下:
在这里插入图片描述
登录(手机号:13800000001,密码:123456):
在这里插入图片描述
可以看到Redis和数据库均显示登录成功:

Redis 数据库
在这里插入图片描述 在这里插入图片描述

同时主界面已经有了回显了:
在这里插入图片描述

总结

本文主要讲解登录的完整流程(前端+后台)。关键点是Controller处理的流程,登录控制层LoginController使用CookieUtils保存token,主页控制层IndexContoller主要通过获取客户端的token来查询用户信息。

发布了2669 篇原创文章 · 获赞 5063 · 访问量 49万+

猜你喜欢

转载自blog.csdn.net/qq_20042935/article/details/104777872