customer.sql


-- ----------------------------
-- Table structure for customer
-- ----------------------------
DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer`  (
  `customer_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
  `customer_pwd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户密码',
  `customer_telno` bigint(0) NOT NULL COMMENT '用户电话',
  `customer_status` int(0) NULL DEFAULT NULL COMMENT '用户状态',
  `customer_create_date` date NULL DEFAULT NULL COMMENT '注册时间',
  `customer_head_img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '头像',
  `customer_update_date` date NULL DEFAULT NULL COMMENT '更改时间',
  `other1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `other2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `custom_cteate_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `custom_update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`customer_id`) USING BTREE,
  UNIQUE INDEX `customertel_index`(`customer_telno`) USING BTREE COMMENT '用户手机号'
) ENGINE = InnoDB AUTO_INCREMENT = 111 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of customer
-- ----------------------------
INSERT INTO `customer` VALUES (1, 'zhang', 'zhang1023', 14506764314, 1, '2001-06-17', 'zhang.png', NULL, NULL, NULL, NULL, NULL);



ConfigRegistCenter.java


package com.example.config;

import com.example.interceptor.JwtInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

@Configuration //将当前类注入到Spring容器中
@EnableWebMvc
public class ConfigRegistCenter implements WebMvcConfigurer {
    //注册拦截器

    public void addInterceptors(InterceptorRegistry registry){

        // "/" 项目根目录(http://localhost:80/app)

        registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/**") //所有资源,包括静态资源
                .excludePathPatterns("/static/**")
                .excludePathPatterns("/customer/login");

    }



    // 静态资源配置
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/","classpath:webapp/");
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }



}




CustomerController.java


package com.example.controller;


import com.example.entity.Customer;
import com.example.service.ICustomerService;
import com.example.util.ServerResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author dd
 * @since 2024-04-10
 */
@Controller
@RequestMapping("customer")
public class CustomerController {
    @Autowired
    private ICustomerService iCustomerService;

    @GetMapping("{customerId}")
    @ResponseBody
    public Customer getById(@PathVariable("customerId") Integer customerId){
        Customer customer = iCustomerService.getById(customerId);
        return customer;
    }


//    @PostMapping("login")
//    public ModelAndView login(String customerName, String customerPwd){
//
//        ServerResult result = iCustomerService.login(customerName, customerPwd);
//        ModelAndView mav = new ModelAndView();
//        if(result.getCode() == 200){
//            mav.addObject("result",result);
//            mav.setViewName("login2");
//        }else{
//            mav.addObject("result",result);
//            mav.setViewName("login");
//        }
//        return mav;
//
//
//    }



    @PostMapping("login")
    @ResponseBody
    public ServerResult login(String customerName, String customerPwd){

        System.out.println("contoller层"+customerName+customerPwd);
        ServerResult result = iCustomerService.login(customerName,customerPwd);
        System.out.println(result);
        return result;
    }

}




Customer.java


package com.example.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;

import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;

/**
 * <p>
 * 
 * </p>
 *
 * @author dd
 * @since 2024-04-10
 */
public class Customer implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 用户id
     */
    @TableId(value = "customer_id", type = IdType.AUTO)
    private Integer customerId;

    /**
     * 用户名
     */
    private String customerName;

    /**
     * 用户密码
     */
    private String customerPwd;

    /**
     * 用户电话
     */
    private Long customerTelno;

    /**
     * 用户状态
     */
    private Integer customerStatus;

    /**
     * 注册时间
     */
    private LocalDate customerCreateDate;

    /**
     * 头像
     */
    private String customerHeadImg;

    /**
     * 更改时间
     */
    private LocalDate customerUpdateDate;

    private String other1;

    private String other2;

    /**
     * 创建时间
     */
    private LocalDateTime customCteateTime;

    /**
     * 更新时间
     */
    private LocalDateTime customUpdateTime;

    public Integer getCustomerId() {
        return customerId;
    }

    public void setCustomerId(Integer customerId) {
        this.customerId = customerId;
    }
    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }
    public String getCustomerPwd() {
        return customerPwd;
    }

    public void setCustomerPwd(String customerPwd) {
        this.customerPwd = customerPwd;
    }
    public Long getCustomerTelno() {
        return customerTelno;
    }

    public void setCustomerTelno(Long customerTelno) {
        this.customerTelno = customerTelno;
    }
    public Integer getCustomerStatus() {
        return customerStatus;
    }

    public void setCustomerStatus(Integer customerStatus) {
        this.customerStatus = customerStatus;
    }
    public LocalDate getCustomerCreateDate() {
        return customerCreateDate;
    }

    public void setCustomerCreateDate(LocalDate customerCreateDate) {
        this.customerCreateDate = customerCreateDate;
    }
    public String getCustomerHeadImg() {
        return customerHeadImg;
    }

    public void setCustomerHeadImg(String customerHeadImg) {
        this.customerHeadImg = customerHeadImg;
    }
    public LocalDate getCustomerUpdateDate() {
        return customerUpdateDate;
    }

    public void setCustomerUpdateDate(LocalDate customerUpdateDate) {
        this.customerUpdateDate = customerUpdateDate;
    }
    public String getOther1() {
        return other1;
    }

    public void setOther1(String other1) {
        this.other1 = other1;
    }
    public String getOther2() {
        return other2;
    }

    public void setOther2(String other2) {
        this.other2 = other2;
    }
    public LocalDateTime getCustomCteateTime() {
        return customCteateTime;
    }

    public void setCustomCteateTime(LocalDateTime customCteateTime) {
        this.customCteateTime = customCteateTime;
    }
    public LocalDateTime getCustomUpdateTime() {
        return customUpdateTime;
    }

    public void setCustomUpdateTime(LocalDateTime customUpdateTime) {
        this.customUpdateTime = customUpdateTime;
    }

    @Override
    public String toString() {
        return "Customer{" +
            "customerId=" + customerId +
            ", customerName=" + customerName +
            ", customerPwd=" + customerPwd +
            ", customerTelno=" + customerTelno +
            ", customerStatus=" + customerStatus +
            ", customerCreateDate=" + customerCreateDate +
            ", customerHeadImg=" + customerHeadImg +
            ", customerUpdateDate=" + customerUpdateDate +
            ", other1=" + other1 +
            ", other2=" + other2 +
            ", customCteateTime=" + customCteateTime +
            ", customUpdateTime=" + customUpdateTime +
        "}";
    }
}




LoginCustomer.java


package com.example.entity;

public class LoginCustomer {
    private Integer customerId;
    private String customerName;


    public LoginCustomer() {
    }

    public LoginCustomer(Integer customerId, String customerName) {
        this.customerId = customerId;
        this.customerName = customerName;
    }


    public Integer getCustomerId() {
        return customerId;
    }

    public void setCustomerId(Integer customerId) {
        this.customerId = customerId;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }
}




JwtInterceptor.java


package com.example.interceptor;

import com.example.util.JwtUtil;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录检查拦截器
 * 被拦截下来的URL:
 * 1.获得token
 * 2.check token
 */
public class JwtInterceptor implements HandlerInterceptor {

    //在访问前拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("登录检查拦截器正在拦截URL>>>"+request.getRequestURI());
        //跨域请求会首先发一个option请求,直接返回正常状态并放行
        //if(request.getMethod().equals("OPTION"))
            //return true;
        //1.获得token
        String token = request.getHeader("token");
        if(token == null || token.equals("")){
            System.out.println("登录检查拦截器正在拦截,没有获得到token");
            //跳转到登录页面
            response.sendRedirect(request.getContextPath()+"/static/login.html");
            return false;
        }else {//2.check token
            System.out.println("登录检查拦截器正在拦截,获得到的token:"+token);
            if (JwtUtil.checkToken(token)){//有效token
                return true;
            }else {
                System.out.println("被拦截了,无效token");
                return false;
            }
        }

//        if(token != null){
//            if(JwtUtil.checkToken(token))
//                return true;//token有效
//        }
//        return false;

    }


}





CustomerMapper.java


package com.example.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.Customer;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author dd
 * @since 2024-04-10
 */
public interface CustomerMapper extends BaseMapper<Customer> {

}




ICustomerService.java



package com.example.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.Customer;
import com.example.util.ServerResult;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author dd
 * @since 2024-04-10
 */
public interface ICustomerService extends IService<Customer> {


    public ServerResult login(String customerName, String customerPwd);

}



CustomerServiceImpl.java


package com.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.Customer;
import com.example.mapper.CustomerMapper;
import com.example.service.ICustomerService;
import com.example.util.JwtUtil;
import com.example.util.ServerResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author dd
 * @since 2024-04-10
 */
@Service
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer>   implements ICustomerService {

    @Autowired
    private CustomerMapper customerMapper;

    @Override
    public ServerResult login(String customerName, String customerPwd){

        System.out.println("seivice层"+customerName+customerPwd);

        QueryWrapper<Customer> wrapper = new QueryWrapper<>();
        wrapper.eq("customer_name",customerName).eq("customer_pwd",customerPwd);
        Customer customer = customerMapper.selectOne(wrapper);
        if(customer != null){
            System.out.println("service层customer 登录");
            String token = JwtUtil.createToken(customer.getCustomerId(),customer.getCustomerName());
            return ServerResult.loginSuccess(token);
        }
        return ServerResult.loginFail("用户登录失败");
    }

}




JwtUtil.java


package com.example.util;


import com.example.entity.LoginCustomer;
import io.jsonwebtoken.*;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtil {

    private static final String jwtToken = "dahkgag7*$";
    private static long expireTime = 1000*60*60*24;



    /**
     * 创建新token
     * @param customerId 用户id
     * @param customerName
     * @return
     */
    public static String createToken(Integer customerId,String customerName){

        Map<String,Object> claims = new HashMap<>();
        claims.put("customerId",customerId);
        claims.put("customerName",customerName);

        System.out.println("创建token"+customerId);
        System.out.println("创建token"+customerName);

        JwtBuilder jwtBuilder = Jwts.builder().signWith(SignatureAlgorithm.HS256,jwtToken)//签发算法(head部分),秘钥为jwtToken
                .setClaims(claims)//body数据,要唯一,自行设。payload部分数据 //1.(customerId,customerName)--token
                .setIssuedAt(new Date())//设置签发时间:保证每次生成的token不同
                .setExpiration(new Date(System.currentTimeMillis()+expireTime));//一天的有效时间

        String token = jwtBuilder.compact();


        return token;
    }

    //验证token是否有效

    /**
     * 验证token是否有效
     * @param token 客户端携带的token
     * @return 返回是否有效
     */
    //2.验证token是否过期
    public static boolean checkToken(String token){
        if(token != null && !token.equals("")){
            try {
                Jwt parse = Jwts.parser().setSigningKey(jwtToken).parseClaimsJws(token);
                return true;
            }catch (ExpiredJwtException e){
                System.out.println("token已经过期了");
                return false;
            } catch (Exception e) {
                System.out.println("无效的token");
                return false;
            }
        }else
            return false;
    }




    /**
     * 解析token中的用户数据
     * @param token 客户端携带的token
     * @return 返回登录用户信息(customerIs)
     */
    public static LoginCustomer parseToken(String token){

        if(token != null && !token.equals("")) {
            try {
                Jwt parse = Jwts.parser().setSigningKey(jwtToken).parseClaimsJws(token);
                Map<String,Object> map = (Map<String, Object>)parse.getBody();
                if(map != null){
                    Integer custId = (Integer)map.get("customerId");//注意,此处的key 要与当初绑定进去的key一致
                    String custName = (String)map.get("customerName");//注意,此处的key 要与当初绑定进去的key一致

                    LoginCustomer loginCustomer = new LoginCustomer(custId,custName);
                    System.out.println("获得到的登录用户的信息是:" + loginCustomer);
                    return loginCustomer;
                }else{
                    System.out.println("获得到的登录用户的信息失败");
                    return null;
                }
            } catch (Exception e){
                e.printStackTrace();
                return null;
            }


        }else
            return null;

    }





}




ServerResult.java



package com.example.util;

public class ServerResult {
    private int code;
    private String msg;

    private Object data;



    public static ServerResult getSuccess(Object data){
        return new ServerResult(200,"查询成功",data);
    }

    public static ServerResult getFail(Object data){
        return new ServerResult(201,"查询失败",data);
    }


    /**
     * 添加、删除、修改的成功
     * @param data
     * @return
     */

    public static ServerResult updateSuccess(Object data){
        return new ServerResult(200,"处理成功",data);
    }


    /**
     * 添加、删除、修改的失败
     * @param data
     * @return
     */
    public static ServerResult updateFail(Object data){
        return new ServerResult(201,"处理失败",data);
    }


    public static ServerResult loginSuccess(Object data){
        return new ServerResult(200,"登录成功",data);
    }

    public static ServerResult loginFail(Object data){
        return new ServerResult(201,"登录失败",data);
    }






    public ServerResult() {
    }


    public ServerResult(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }


    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }


    @Override
    public String toString() {
        return "ServerResult{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}



ServletInitializer.java


package com.example;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringbootLoginApplication.class);
    }

}




SpringbootLoginApplication.java


package com.example;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.example.mapper")
public class SpringbootLoginApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootLoginApplication.class, args);
    }

}




application.yaml


server:
  servlet:
    context-path: /app
  port: 80

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/dicts?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
  mvc:
    view:
      prefix: / #前缀
      suffix: .jsp #后缀
    hiddenmethod:
      filter:
        enabled: true # 支持表单 method 转换

logging:
  file:
    path: d://logger #日志记录
  level:
    com.example: debug




css_04_首页.css


*{
    margin: 0;
    padding: 0;
}
/* =======================头部======================= */
.header{
    width: 85%;   /*  %: 父元素(父标签的百分比)*/
    height: 58px;
    /* background-color: aquamarine; */
    min-width: 1000px;
    margin: 0 auto;  /*容器水平居中*/
}

/* =======================logo部分 =======================*/
.header .logo{
    width: 15%;
    height: 33px;
    /* background-color: #fa8072; */
    float: left;   /*不换行*/
    margin-top: 12px;  /*距离顶部间距*/
}

.header .logo a{  /*行内元素不能设置宽高度,转换成 inline-block / block*/
    display: inline-block;
    width: 100%;
    height: 33px;
    background: url(../images/header-small-sprites3.png) no-repeat 0 -25px;
    background-size: 125px;
}




/*======================= 导航部分 =======================*/
.header .nav{
    width: 35%;
    height: 100%;
    /* background-color: skyblue; */
    float: left;
    min-width: 450px;
}

/* 1.设置UL 宽高度 : 100%
2.小黑点去掉UL
3.Li 不换行 : float :left 
4.设置每个li 宽高度
5.A 超链接宽高度 = li 宽高度
6.设置a超链接文字的大小,居中,下划线
7.鼠标悬浮样式修改 a:hover */

.nav .head-nav{
  width: 100%;
  height: 100%;
  /* background-color: burlywood; */
  list-style: none;  /*小黑点去掉UL*/
}

.head-nav li{
    float: left;  /*不换行 */
    height: 100%;
    width: 80px;
   /* border-right: 1px dotted white;  solid : 实线 , dashed: 虚线 , dotted : 圆点*/
}

.head-nav li a{
    display: inline-block;
    width: 100%;
    height: 100%;
    color: rgb(78, 78, 78);
    text-decoration: none; /*超链接下划线去除*/
    font-size: 13px;
    text-align: center;
    line-height: 58px;
}
.head-nav li a:hover{  /*鼠标悬浮样式修改 */
    background-color: rgba(230, 69, 102, 0.1);
    color: rgb(78, 78, 78);
    border-bottom: 3px solid rgba(230, 69, 102, 0.1)
}

.head-nav .first-item{  /*第一个li ,首页*/
    background-color: rgba(230, 69, 102, 0.1);
    color: rgb(78, 78, 78);
}
.head-nav .first-item:hover{ /*第一个li ,首页,鼠标悬浮不变*/
    background-color: rgba(230, 69, 102, 0.1);
    color: rgb(78, 78, 78);
    border-bottom:none;
}


/* =====================搜索区域=========================== */
.search{
    width: 25%;
    height: 100%;
      /* background-color: yellow;  */
    float: left;
    min-width: 260px;
}


.search form{
    width: 100%;
    height: 30px;
    /* background-color: aqua; */
    margin-top: 12px;
   
}
/* 搜索框 */
.search form .search-kw{
    width: 180px;
    height: 100%;
    border: 1px solid rgba(230, 69, 102, 0.1);
    border-radius: 4px;
   outline: none; /*点击输入框的内边框 取消*/
   padding-left: 10px;/*内部的文字 左间距 : 左内间距*/
   color:  rgb(108, 108, 108);
}

/* 搜索按钮 */
.search .search-btn{
    width: 60px;
    height: 30px;
    background-color: rgba(230, 69, 102, 0.1);
    font-size: 12px;
    color: rgb(78, 78, 78);
    border: none;
    cursor: pointer ;  /*鼠标悬浮上去 是小手链接形状*/
    border-radius: 4px;
}

/*======================= 登录区域======================= */
.header  .login{
    
    width: 13%;
    height: 100%;
    /* background-color: yellow; */
    float: right;
}

.login a{
    display: inline-block;
    width: 60px;
    height: 30px;
    background-color: rgba(230, 69, 102, 0.1);
    margin-top: 14px;  /*上间距*/
    border-radius: 4px;  /*圆角*/
    text-decoration: none;
    color: rgb(78, 78, 78);
    font-size: 12px;
    text-align: center;
    line-height: 30px;
}

.login a:hover{  /*:hover  鼠标悬浮*/
    /* background-color:white;
    color: rgba(230, 69, 102, 0.1); */
    /* border: 1px solid rgba(230, 69, 102, 0.1); */
    font-weight: bold;
}


/* ==========================banner======================== */
.banner{
    width: 100%;
    height: 400px;
    /* background-color: salmon; */
}

.banner img{
    width: 100%;
    height: 100%;
}

/*    =======================  热门商品==================  */
.pro-title{
    width: 100%;
    height: 80px;
    /* background-color: salmon; */
    text-align: center;
    line-height: 80px;
    font-size: 28px;
}
/* 商品列表 */
.pro-list{
    width: 85%;
    height: 660px;
    /* background-color: skyblue;  */
   margin:  0 auto; /* 容器居中 */
}

.pro-list ul{
    width: 100%;
    height:  100%;
    list-style: none;
}

.pro-list ul li{
    width: 230px;
    height: 320px;
    /* border: 3px solid salmon; */
    float: left;  /* 不换行 */
    margin-right: 30px;
    margin-bottom: 10px;

}

.pro-list ul li img{
    width: 160px;
    height: 160px;
    /* background-color: sandybrown; */
}

.pro-list ul  .pro-name{
    width: 190px;
    height: 48px;
    /* background-color: chartreuse; */
    margin-left: 20px;
    font-size: 13px;
    color: darkgrey;
    text-align: center;
}
.pro-name-a{
    text-decoration: none;
}
.pro-list ul  .pro-price{
    width: 190px;
    height: 18px;
    /* background-color: antiquewhite; */
    margin-left: 20px;
    margin-top: 10px;
    text-align: center;
    color: rgba(230, 69, 101, 0.591);

}

.pro-price i{
    vertical-align: middle;
    font-size: 12px;
    font-weight: 700;
    font-family: MicrosoftYahei-regular,Arial,Helvetica,sans-serif;
}



css_11_login.css



*{
    margin:0;
    padding: 0;
}

body{
    background : rgba(230, 69, 102, 0.1); /*背景图片*/
}

.login_form{
    width: 440px;
    height: 350px;
    background-color: white;
    margin: 0 auto;
    margin-top: 80px; 
    border-radius: 6px;/*圆角*/ 
}

.form_title{
    height: 80px;    
    line-height: 80px ;  /* line-height = height   */
    text-align: center;
    color: rgba(113,115,118,1);;
    font-family: PingFangSC-Regular,PingFang SC; /*字体*/
    font-size: 18px;
}

.myform{
    width: 80%;
    height: 280px;
   
    margin: 0 auto;
    margin-top: 40px; 
}
.myform .user_name,.user_pwd{
    width: 320px;
    height: 40px;
    display: block;
    margin:  0 auto;
    margin-bottom: 20px;
    border-radius: 4px;
    outline: none;  
    border:none;
    background-color: #f6f7f9;
    padding-left: 10px;
    padding-right: 10px;
}


.myform .loginBtn{
    width: 320px;
    height: 42px;
    background-color: rgba(230, 69, 102, 0.1);
    color: rgb(146, 145, 145);
    display: block;
    margin:  0 auto;
    margin-top: 10px;
    border: none;
    border-radius: 4px;
}

.myform .loginBtn:hover{
    background-color: rgba(230, 69, 101, 0.196);
}

.login_tip{
    display: block;
    width: 340px;
    height: 30px;
    font-size: 10px;
    color: red;
    text-align: center;
}
 


js_02_登录验证.js


// document : HTML 网页文档
// query 查询, Selector 选择器
var loginTip = document.querySelector(".login_tip");
var usernameEle = document.querySelector(".user_name");
//onblur : 光标移开输入框
usernameEle.onblur = checkUsername;
// 验证用户名
function checkUsername(){
    var username = usernameEle.value;
    console.log("用户名是:" + username)
   
    if(username == '' || username.length ==0){
        loginTip.innerText = '用户名不能为空';
        return false;
    }else{
        loginTip.innerText = '';
        return true;
    }
  
}

// 光标移开密码域,验证密码是否为空
var userPwdEle = document.querySelector('.user_pwd');
userPwdEle.onblur = checkUserPwd;
// 验证密码
function checkUserPwd(){
    var userPwd = userPwdEle.value;
    if(userPwd =='' || userPwd.length == 0){
        loginTip.innerText = '密码不能为空';
        return false;
    }else{
        loginTip.innerText = '';
        return true;
    }
}

// 登录表单提交验证
document.querySelector(".myform").onsubmit = function(){
      var result  =  checkUsername() && checkUserPwd();
      console.log(result);
      return result;
}



index.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>首页</title>
    <link href="css/css_04_首页.css" rel="stylesheet"/>
    <link rel="shortcut icon" href="images/favicon.ico" />
</head>
<body>
<!-- ======================1. 头部 ======================-->
<div class="header">
    <div class="logo">
        <a href=""> </a>
    </div>

    <div class="nav">
        <ul class="head-nav">
            <li><a href="" class="first-item">首页</a></li>
            <li><a href="">菜品</a></li>
            <li><a href="">店铺</a></li>
            <li><a href="">热卖</a></li>
            <li><a href="">优惠券</a></li>

        </ul>
    </div>

    <div class="search">
        <form>
            <input type="text" class="search-kw" >
            <input type="submit" class="search-btn" value="搜索"/>
        </form>
    </div>
    <div class="login">
        <a href="login.html">登录</a>
        <a href="">注册</a>
    </div>
</div>

<!-- ======================2. 横幅 banner ======================-->
<div class="banner">
    <img src="images/bg1.jpg" />
</div>


<!-- =======================3. 热门商品================== -->
<h3 class="pro-title"> 热门商品</h3>
<div class="pro-list">
    <ul>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro2.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro3.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro2.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro3.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro2.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro3.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro2.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>
        <li>
            <a href="css_06_商品详情.html">
                <img class="pro-img" src="images/pro3.webp" />
            </a>

            <a href="" class="pro-name-a">
                <p  class="pro-name">HUAWEI Mate X5 典藏版 16GB+1TB 青山黛</p>
            </a>

            <div class="pro-price">
                <i></i>
                <span>6999.00</span>
            </div>
        </li>


    </ul>
</div>


</body>
</html>



login.html


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="css/css_11_login.css" />
  <script src="js/jquery-3.7.0.min.js"></script>

</head>
<body>
<div class="login_form">
  <h4 class="form_title">登录</h4>

  <form class="myform" method="post" >
    <span class="login_tip"></span>
    <input type="text"  class="user_name" placeholder="您的邮箱或手机号" name="customerName"/>
    <input type="password"  class="user_pwd"  placeholder="您的密码" name="customerPwd"/>
    <input type="button" value="登录" class="loginBtn">
  </form>
</div>


<script src="js/js_02_登录验证.js"></script>



<script>
  $(".loginBtn").click(function (){
    var url = "http://localhost:80/app/customer/login";
    var formData = $(".myform").serialize();
    $.post(url,formData,function (result){
      console.log(result)
      if(result.code ==200){
        localStorage.setItem("token",result.data);  // 1.保存token
        window.location.href = "index.html";
      }else{
        $(".login_tip").text(result.data);
      }
    })
  })
</script>
</body>
</html>



pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot_login</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>springboot_login</name>
    <description>springboot_login</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.9</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.0</version>
        </dependency>











        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>




        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generate -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>




04-20 17:04