微服务商城系统 实战记录 用户、商家、后台管理员注册与登录功能实现

代码见 https://github.com/betterGa/ChangGou


     现在整个商城系统的后端逻辑基本上都实现了,接下来需要与前端页面联调起来。

一、用户注册

     用户注册需要以下信息:
在这里插入图片描述
(注意到 created、updated 都是不为 null 的,所以需要对 UserServiceImpl 的 add 方法进行设置:

 public void add(User user){

        // 设置创建时间和更新时间为当前时间
        Date created=new Date();
        Date updated=new Date();

        user.setCreated(created);
        user.setUpdated(updated);

        userMapper.insert(user);
    }


前端页面:
在这里插入图片描述

对应后端方法:

 /***
     * 新增User数据
     * @param user
     * @return
     */
    @PostMapping
    public Result add(@RequestBody   User user){
        //调用UserService实现添加User
        userService.add(user);
        return new Result(true,StatusCode.OK,"添加成功");
    }

需要先对该路径进行放行:
在这里插入图片描述

进行测试:
在这里插入图片描述
接下来需要由前端传来数据。前端页面调用后端端口,使用 ajax,

1、使用 ajax (POST 方法)

     使用 ajax 之前需要先导入 jquery 依赖,jQuery 是一个 JavaScript 函数库, 是一个轻量级的 “写的少,做的多” 的 JavaScript 库,其中包含 ajax 功能。在 js 文件夹下拷贝 jquery.js 文件,并且把引入 jquery.js 的 放在前面,不能写在一个标签里。

<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript">

整个 script 代码:

<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript">
    function entity(username, password, email, phone) {
        this.username = username;
        this.password = password;
        this.email = email;
        this.phone = phone;
    }

    $(function () {
        $('#registerBut').on('click', function () {
                var username = $('#username').val()
                var password = $('#password').val()
                var email = $('#email').val()
                var phone = $('#phone').val()
                returnData = new entity(username, password, email, phone);
                $.ajax(
                    {
                        url: "http://localhost:18087/user",
                        type: "POST",
                        dataType: "JSON",
                        contentType: "application/json;charset=UTF-8",
                        data: JSON.stringify(returnData),
                        success: function (result) {
                            alert("注册成功!");
                        },
                        error: function (result) {
                            console.log(result);
                            alert("用户名重复!");
                        },
                        cache: false
                    }
                )
            }
        )
    })
</script>

     在 jquery 中,$ 是常用的一个回传函数,定义为 “选取” , 英文是 selector 的缩写,表示选取。
$.function(); 就是 选取 JQuery 定义的 function() 执行。
$('input') 就是 选取 HTML 当中全部的 input 标签。
$('#abc') 就是 选取 HTML 当中 ID 名称为 abc 的物件。
$.fn.testing = function() {} 就是 选取 JQuery 内核函数 fn (函数) 回传给 testing 这个名称、定义为一个功能 function()。
    
    把 script 标签写在 head 之后,body 之前,这样会先加载 script ,再加载页面,因为页面的 “完成登录” 按钮:

<button class="sui-btn btn-block btn-xlarge btn-danger" type="button" target="_blank"
                                id="registerBut">完成注册</button>

     JQuery 的代码通常会包裹在一个 $(function(){}) 函数中,$(function(){}) 也就是 $(document).ready(function(){}) 的简写,与之对应的原生 js 的window.onload 事件。
     注意 ,ajax 里面的 data 不能是 json 格式,否则会报 400、415 错误状态码。

2、使用 thymeleaf

     访问后端端口时,渲染前端页面,使用 thymeleaf,新建子工程 changgou-web-register,因为父工程 web 工程里已经导入过 thymeleaf 依赖了,所以子工程就不需要导了(实际上清除缓存并重启了一次整个项目之后,thymeleaf 才奏效)
     此处踩了个坑,使用 thymeleaf 需要确保 Controller 类 放在与 @SpringBootApplication 注解的启动类 相同包 或者 子包 下。

@Controller
    @RequestMapping("/user")
    public class RegisterController {
        @CrossOrigin
        @GetMapping("/register")
        public String search() {
            return "register";
        }
    }

在这里插入图片描述

     集成好 thymeleaf 后,通过后端控制层路径可以访问到前端页面了,但是现在没有加载出样式。
在这里插入图片描述
原先 css 路径:

 <link rel="stylesheet" type="text/css" href="../static/css/all.css" />
    <link rel="stylesheet" type="text/css" href="../static/css/pages-register.css" />

注意,Thymeleaf 使用的是绝对路径,而不是相对路径。
需要把路径修改为:

 <link rel="stylesheet" type="text/css" href="/css/all.css" />
    <link rel="stylesheet" type="text/css" href="/css/pages-register.css" />

(因为我们在 application.yml 中配置过了:
在这里插入图片描述
有空了去掉,再看看效果。)
同样地,jquery 的路径也需要修改:

<script type="text/javascript" src="/js/jquery.js"></script>

至此,通过 http://localhost:18094/user/register 可以访问到用户登录页面。
在这里插入图片描述

     启动 changgou-web-register,访问 http://localhost:18094/user/register ,这时出现了问题,它弹框 “用户名重复”,而此时到数据库中查看,新增记录是成功的。
     根本原因在于,在进行 post 请求之前,进行了一次 options 请求。
     众所周知, ajax 请求是由 XMLHttpReques 对象实现的 (部分低版本ID浏览器不是), 而 XMLHttpRequest 会遵守 同源策略(same-origin policy). 也就是说,脚本只能访问 相同协议/相同主机名/相同端口 的资源, 如果要突破这个限制, 那就是所谓的 跨域 , 此时需要遵守 CORS(Cross-Origin Resource Sharing) 机制。也就是说,现在 http://localhost:18094/user/register 的 register.html 代码的 ajax 中,试图访问 http://localhost:18087/user ,跨域了。
     而在 W3C 规范中,跨域请求,分为简单请求(GET ;HEAD; POST;除了使用用户代理自动生成的 headers,或者在 Fetch 规范中定义为 “forbidden header name” 的其他 headers,只有以下 headers 被允许用作 人工地设置为 Fetch 规范定义为 “CORS-safelisted request-header” :Accept,Accept-Language,Content-Language,Content-Type;content-type 是 application/x-www-form-urlencoded、multipart 或 text/plain ;XMLHttpRequest对象发出的请求 ) 和复杂请求。而复杂请求发出之前,就会出现一次 options 请求。
(简单请求的定义见 https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_request_headers:
在这里插入图片描述

     options 请求是一种探测性的请求,通过这个方法,客户端可以在采取具体资源请求之前,决定对该资源采取何种必要措施,或者了解服务器的性能。
     在 ajax 中,跨域请求时,json,就属于复杂请求,因此需要提前发出一次 options 请求,用以检查请求是否是可靠安全的,如果 options 获得的回应是拒绝性质的,比如 404\403\500 等 http 状态,就会停止 post、put 等请求的发出。
    在代码中, ajax 使用的是跨域请求,而且 contentType 使用的是 application/json,归为复杂请求啦,就会在 POST 方法之前,先使用 OPTIONS ,所以会出现重复提交的情况。
    把请求整成不跨域的就OK。

3、解决跨域问题

    在 UserController 上使用 @CrossOrigin 支持跨域(这里好像也是需要清除缓存、重新启动项目才能奏效 ),然后进行测试:
在这里插入图片描述

现在还有个问题,如果用户名重复的话:
在这里插入图片描述
控制台:
在这里插入图片描述
     后台代码并没有对这样的情况捕获异常,等之后对异常处理熟悉了之后,考虑完善这里的逻辑。
【已解决】在插入数据之前先对数据进行查询,如果已经存在记录,返回 false:

@Override
    public boolean add(User user) {
        if (userMapper.selectByPrimaryKey(user) == null) {
        
            // 设置创建时间和更新时间为当前时间
        	Date created = new Date();
        	Date updated = new Date();
        	
        	// 设置用户使用状态为正常
            user.setStatus("1");
           
            user.setCreated(created);
            user.setUpdated(updated);
            userMapper.insert(user);
            return true;
        }
        // 如果数据库中已经存在用户名,返回 false
        return false;
    }
 @PostMapping
    public Result add(@RequestBody   User user){
        //调用UserService实现添加User
       boolean isInsert=userService.add(user);
       if(isInsert){
        return new Result(true,StatusCode.OK,"添加成功");}
       else return new Result(false,StatusCode.LOGINERROR,"添加失败,用户名重复");
    }

    
在 ajax 中修改逻辑,根据调用接口的返回值进行提示:

 $.ajax(
                {
                    url: "http://localhost:18087/user",
                    type: "POST",
                    dataType: "JSON",
                    contentType: "application/json;charset=UTF-8",
                    data: JSON.stringify(returnData),
                    success: function (result) {
                        var flag=result.flag;
                      if(flag===true){
                        alert("注册成功!");}
                      else alert("用户名重复!");
                    },
                    error: function (result) {
                        console.log(result);
                        alert("访问用户注册接口失败!");
                    },
                    cache: false
                }
            )

二、用户登录

前端登录页面是这样的:在这里插入图片描述
     用户登录的逻辑是,到数据库中校验邮箱/用户名/手机号和密码,一致的话,跳转至商城首页。
     需要先提供校验的逻辑:
在 mapper 中使用 SQL 语句:

  @Select("SELECT * FROM tb_user where (password=#{password} and email=#{param1} or (password=#{password} and phone=#{param1} or (password=#{password} and username=#{param1})")
    void registerCheck(String param1, String password);

服务层:

@Override
    public User registerCheck(String param1, String password) {
        List<User> users = userMapper.registerCheck(param1, password);
        // 查询无果
        if (users == null || users.size() == 0) return null;
        else return users.get(0);
    }

控制层:

 @GetMapping("/login")
    public Result registerCheck(@RequestParam(value = "param") String param1,@RequestParam("password") String password) {
        User user = userService.registerCheck(param1,password);
        if (user == null) {
            return new Result(false, StatusCode.ERROR, "用户不存在");
        } else {
            return new Result(true, StatusCode.OK, "用户登录校验成功", user);
        }
    }

测试结果:
在这里插入图片描述
在这里插入图片描述
需要对该路径进行放行:
在这里插入图片描述

1、ajax 使用 GET 方法

     使用 ajax 调用该 GET 方法,并把参数传过去,data 要求为 Object 或 String 类型的参数,发送到服务器的数据。如果已经不是字符串,将自动转换为字符串格
式。get 请求中将附加在 url 后。防止这种自动转换,可以查看 processData 选项。对象必须为key/value 格式,例如 {foo1:“bar1”,foo2:“bar2”} 转换为 &foo1=bar1&foo2=bar2 。如果是数组,JQuery 将自动为不同值对应同一个名称。例如 {foo:[“bar1”,“bar2”]} 转换为 &foo=bar1&foo=bar2。

设置登录按钮:

 <button class="sui-btn btn-block btn-xlarge btn-danger" target="_blank"
id="loginBut" type="button">&nbsp;&nbsp;</button>

注意:这里的 type=button 是必须的,否则后续点击后无法完成跳转到其他页面。
使用 ajax 访问登录接口:

<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript">
    $(function () {
        $('#loginBut').on('click', function () {
            $.ajax(
                {
                    url: "http://localhost:18087/user/login",
                    type: "GET",
                    dataType: "JSON",
                    contentType: "application/json;charset=UTF-8",
                    data: {param: $('#inputName').val(), password: $('#inputPassword').val()},
                    success: function (result) {
                        var flag = result.flag;
                        if (flag === true) {
                            var status = result.data.status;
                            if (status == 1) {
                                alert("登录校验成功!即将跳转至商城首页");
                                window.location.href = "http://localhost:18086/search/list";
                            } else {
                                alert("用户使用状态异常,已被限制访问");
                            }
                        } else alert("用户不存在,请重新登录或注册!");
                    },
                    error: function (result) {
                        console.log(result);
                        alert("访问用户登录接口失败!");
                    },
                    cache: false
                }
            )
        })
    })
</script>

三、商家注册

前端页面:
在这里插入图片描述

1、dao、service、controller 层搭建

数据库建表:

CREATE TABLE `tb_store` (
  `storename` varchar(50) NOT NULL COMMENT '商家名称',
  `password` varchar(100) NOT NULL COMMENT '商家密码',
  `invitecode` varchar(50) NOT NULL COMMENT '平台邀请码',
  `centerstatus` varchar(1) DEFAULT NULL COMMENT '入驻状态。1表示允许入驻,0表示未入驻',
  `created` datetime DEFAULT NULL COMMENT '创建时间',
  `updated` datetime DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`storename`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

dao 层继承通用 mapper:

public interface StoreMapper extends Mapper<Store> {
}

服务层实现:

@Service
public class StoreServiceImpl implements StoreService {
    @Autowired
    StoreMapper storeMapper;

 @Override
    public boolean add(Store store) {
        Store storeResult = storeMapper.selectByPrimaryKey(store);
        if (storeResult == null) {
            Date date = new Date();
            store.setUpdated(date);
            store.setCreated(date);
            // 设置状态未入驻
            store.setCenterStatus("0");

            storeMapper.insert(store);
            // 插入成功
            return true;
        }
        // 说明商户名已存在,返回插入失败
        return false;
    }

控制层:

@RestController
@RequestMapping("/store")
public class StoreController {

    @Autowired
    StoreService storeService;

    @CrossOrigin
    @PostMapping("/register")
    public Result register(@RequestBody Store store) {
        boolean isSuccess = storeService.add(store);
        if (isSuccess) {
            return new Result(true, StatusCode.OK, "插入商家记录成功");
        } else return new Result(false, StatusCode.ERROR, "用户名已存在,插入失败");
    }

测试结果:
在这里插入图片描述
在这里插入图片描述
ajax 逻辑:

 $.ajax(
                    {
                        url: "http://localhost:18089/store/register",
                        type: "POST",
                        dataType: "JSON",
                        contentType: "application/json;charset=UTF-8",
                        data: JSON.stringify(returnData),
                        success: function (result) {
                            var flag=result.flag;
                          if(flag===true){
                            alert("注册成功!");}
                          else alert("商家名重复!");
                        },
                        error: function (result) {
                            console.log(result);
                            alert("访问商家注册接口失败!");
                        },
                        cache: false
                    }
                )

四、商家登录

前端页面:
在这里插入图片描述
服务层实现:

@Override
public Store checkLogin(String storeName, String password) {
    Store store=new Store();
    store.setStoreName(storeName);
    store.setPassword(password);

    List<Store> storeList=storeMapper.select(store);
    // 查询无果
    if(storeList==null||storeList.size()==0){
        return null;
    }else {
    return storeList.get(0);}
}

控制层:

@CrossOrigin
    @GetMapping("/login")
    public Result login(@RequestParam(value = "storeName") String storename,
                        @RequestParam(value = "password") String password) {
        Store store=storeService.checkLogin(storename, password);
        if (store!=null) {
            return new Result(true, StatusCode.OK, "登录成功!",store);
        } else {
            return new Result(false, StatusCode.ERROR, "登录失败,查询无果!");
        }
    }

测试结果:
在这里插入图片描述
前端调用 ajax 逻辑:

 $.ajax(
            {
                url: "http://localhost:18089/store/login",
                type: "GET",
                dataType: "JSON",
                contentType: "application/json;charset=UTF-8",
                data: {storeName: $('#storeName').val(), password: $('#inputPassword').val()},
                success: function (result) {
                    var flag = result.flag;
                    if (flag === true) {
                        var centerStatus = result.data.centerStatus;
                        if (centerStatus == 1) {
                            alert("登录校验成功!即将跳转至商家管理页面");
                            window.location.href = "http://localhost:18086/search/list";
                        } else {
                            alert("商家未入驻,需等待管理员审核");
                        }
                    } else alert("商家不存在,请重新登录或注册!");
                },
                error: function (result) {
                    console.log(result);
                    alert("访问用户登录接口失败!");
                },
                cache: false
            }
        )

五、后台管理员登录

不在后端代码中做逻辑判断,只是在 js 里判断用户名和密码是否同时是 “admin”,是的话登录成功,后续跳转到管理页面,否则提示登录失败。

<script type="text/javascript">
    function login(username, password) {
        if (username === 'admin' && password === 'admin') {
            alert('登录成功,即将进入管理页面');
            //window.location.href('');
        } else alert('请输入正确的管理员用户名和密码');
    }

</script>
  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值