电商项目:畅购商城4.0

1. 走进电商

1.1 电商行业分析

近年来,世界经济正向数字化转型,大力发展数字经济成为全球共识。党的十九大报告明确提出要建设“数字中国”“网络强国”,我国数字经济发展进入新阶段,市场规模位居全球第二,数字经济与实体经济深度融合,有力促进了供给侧结构性改革。电子商务是数字经济的重要组成部分,是数字经济最活跃、最集中的表现形式之一。
我国电子商务交易规模继续扩大,全国电子商务交易额达保持高速增长。国家统计局数据显示,2017年29.16万亿元,2018年31.64万亿元,2019年34.81万亿元,2020年交易额达38.21万亿元。
最近几年天猫双十一成交额

在这里插入图片描述

1.2 主要电商模式

  • B2B
    B2B ( Business to Business)是指进行电子商务交易的供需双方都是商家(或企业、公司),她(他)们使用了互联网的技术或各种商务网络平台,完成商务交易的过程。电子商务是现代 B2B marketing的一种具体主要的表现形式。
    案例:阿里巴巴、慧聪网

  • C2C
    C2C即 Customer(Consumer) to Customer(Consumer),意思就是消费者个人间的电子商务行为。比如一个消费者有一台电脑,通过网络进行交易,把它出售给另外一个消费者,此种交易类型就称为C2C电子商务。
    案例:淘宝、易趣、瓜子二手车

  • B2C
    B2C是Business-to-Customer的缩写,而其中文简称为“商对客”。“商对客”是电子商务的一种模式,也就是通常说的直接面向消费者销售产品和服务商业零售模式。这种形式的电子商务一般以网络零售业为主,主要借助于互联网开展在线销售活动。B2C即企业通过互联网为消费者提供一个新型的购物环境——网上商店,消费者通过网络在网上购物、网上支付等消费行为。
    案例:唯品会、乐蜂网

  • C2B
    C2B(Consumer to Business,即消费者到企业),是互联网经济时代新的商业模式。这一模式改变了原有生产者(企业和机构)和消费者的关系,是一种消费者贡献价值(Create Value), 企业和机构消费价值(Consume Value)。

C2B模式和我们熟知的供需模式(DSM, Demand SupplyModel)恰恰相反,真正的C2B 应该先有消费者需求产生而后有企业生产,即先有消费者提出需求,后有生产企业按需求组织生产。通常情况为消费者根据自身需求定制产品和价格,或主动参与产品设计、生产和定价,产品、价格等彰显消费者的个性化需求,生产企业进行定制化生产。
案例:海尔商城、 尚品宅配

  • O2O
    O2O即Online To Offline(在线离线/线上到线下),是指将线下的商务机会与互联网结合,让互联网成为线下交易的平台,这个概念最早来源于美国。O2O的概念非常广泛,既可涉及到线上,又可涉及到线下,可以通称为O2O。主流商业管理课程均对O2O这种新型的商业模式有所介绍及关注。
    案例:美团、饿了吗

  • B2B2C
    B2B2C是一种电子商务类型的网络购物商业模式,B是BUSINESS的简称,C是CUSTOMER的简称,第一个B指的是商品或服务的供应商,第二个B指的是从事电子商务的企业,C则是表示消费者。

案例:京东商城、天猫商城

  • 注:《畅购电商系统开发》采用B2C模式

2. 畅购前台-需求分析与系统设计

  • 电商项目分为:前台和后台
  • 前台:提供用户使用
  • 后台:提供商家进行管理

2.2 系统设计

在这里插入图片描述

2.2.1 技术架构

在这里插入图片描述

3. 架构搭建

3.1 后端环境

3.2.1 父工程:changgou4_parent_ali

  • 修改pom.xml文件,确定spring boot、spring cloud、spring cloud Alibaba 等版本
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.czxy.changgou</groupId>
  <artifactId>changgou4-parent-ali</artifactId>
  <packaging>pom</packaging>
  <version>1.0-SNAPSHOT</version>
  <modules>
      <module>changgou4_common</module>
      <module>changgou4_common_auth</module>
      <module>changgou4_common_db</module>
      <module>changgou4_gateway</module>
      <module>changgou4_pojo</module>
      <module>changgou4_service_web</module>
  </modules>

  <!-- 1 确定spring boot的版本-->
  <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.2.5.RELEASE</version>
  </parent>

  <!--2  确定版本-->
  <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <java.version>1.8</java.version>
      <spring-cloud-release.version>Hoxton.SR3</spring-cloud-release.version>
      <nacos.version>1.1.0</nacos.version>
      <alibaba.cloud.version>2.2.1.RELEASE</alibaba.cloud.version>
      <mysql.version>5.1.32</mysql.version>
      <mybatis.plus.version>3.4.0</mybatis.plus.version>
      <druid.starter.version>1.1.9</druid.starter.version>
      <jwt.jjwt.version>0.9.0</jwt.jjwt.version>
      <jwt.joda.version>2.9.7</jwt.joda.version>
      <swagger.version>2.7.0</swagger.version>
      <beanutils.version>1.9.3</beanutils.version>
      <aliyun.sdk.core.version>3.3.1</aliyun.sdk.core.version>
      <aliyun.sdk.dysmsapi.version>1.0.0</aliyun.sdk.dysmsapi.version>
      <changgou4.common.version>1.0-SNAPSHOT</changgou4.common.version>
      <changgou4.common.auth.version>1.0-SNAPSHOT</changgou4.common.auth.version>
      <changgou4.common.db.version>1.0-SNAPSHOT</changgou4.common.db.version>
      <changgou4.pojo.version>1.0-SNAPSHOT</changgou4.pojo.version>

  </properties>

  <!-- 3 锁定版本-->
  <dependencyManagement>
      <dependencies>
          <!-- sprig cloud-->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-dependencies</artifactId>
              <version>${spring-cloud-release.version}</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
          <!--nacos -->
          <dependency>
              <groupId>com.alibaba.nacos</groupId>
              <artifactId>nacos-client</artifactId>
              <version>${nacos.version}</version>
          </dependency>

          <!--nacos cloud 发现 -->
          <dependency>
              <groupId>com.alibaba.cloud</groupId>
              <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
              <version>${alibaba.cloud.version}</version>
          </dependency>

          <!--nacos cloud 配置 -->
          <dependency>
              <groupId>com.alibaba.cloud</groupId>
              <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
              <version>${alibaba.cloud.version}</version>
          </dependency>

          <!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-sentinel -->
          <dependency>
              <groupId>com.alibaba.cloud</groupId>
              <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
              <version>${alibaba.cloud.version}</version>
          </dependency>

          <!-- mybatis plus-->
          <dependency>
              <groupId>com.baomidou</groupId>
              <artifactId>mybatis-plus-boot-starter</artifactId>
              <version>${mybatis.plus.version}</version>
          </dependency>
          <dependency>
              <groupId>com.baomidou</groupId>
              <artifactId>mybatis-plus-annotation</artifactId>
              <version>${mybatis.plus.version}</version>
          </dependency>

          <!-- mysql驱动 -->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>${mysql.version}</version>
          </dependency>

          <!-- druid启动器 -->
          <dependency>
              <groupId>com.alibaba</groupId>
              <artifactId>druid-spring-boot-starter</artifactId>
              <version>${druid.starter.version}</version>
          </dependency>

          <!--swagger2-->
          <dependency>
              <groupId>io.springfox</groupId>
              <artifactId>springfox-swagger2</artifactId>
              <version>${swagger.version}</version>
          </dependency>
          <dependency>
              <groupId>io.springfox</groupId>
              <artifactId>springfox-swagger-ui</artifactId>
              <version>${swagger.version}</version>
          </dependency>

          <!--jwt-->
          <!--JavaBean工具类,用于JavaBean数据封装-->
          <dependency>
              <groupId>commons-beanutils</groupId>
              <artifactId>commons-beanutils</artifactId>
              <version>${beanutils.version}</version>
          </dependency>

          <!--jwt工具-->
          <dependency>
              <groupId>io.jsonwebtoken</groupId>
              <artifactId>jjwt</artifactId>
              <version>${jwt.jjwt.version}</version>
          </dependency>

          <!--joda 时间工具类 -->
          <dependency>
              <groupId>joda-time</groupId>
              <artifactId>joda-time</artifactId>
              <version>${jwt.joda.version}</version>
          </dependency>

          <!--短信-->
          <dependency>
              <groupId>com.aliyuncs</groupId>
              <artifactId>aliyun-java-sdk-core</artifactId>
              <version>${aliyun.sdk.core.version}</version>
          </dependency>
          <dependency>
              <groupId>com.aliyuncs.dysmsapi</groupId>
              <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
              <version>${aliyun.sdk.dysmsapi.version}</version>
          </dependency>

          <!--自定义项目-->
          <dependency>
              <groupId>com.czxy.changgou</groupId>
              <artifactId>changgou4_common</artifactId>
              <version>${changgou4.common.version}</version>
          </dependency>
          <dependency>
              <groupId>com.czxy.changgou</groupId>
              <artifactId>changgou4_common_auth</artifactId>
              <version>${changgou4.common.auth.version}</version>
          </dependency>
          <dependency>
              <groupId>com.czxy.changgou</groupId>
              <artifactId>changgou4_common_db</artifactId>
              <version>${changgou4.common.db.version}</version>
          </dependency>
          <dependency>
              <groupId>com.czxy.changgou</groupId>
              <artifactId>changgou4_pojo</artifactId>
              <version>${changgou4.pojo.version}</version>
          </dependency>


      </dependencies>

  </dependencyManagement>

</project>

3.2.2 公共项目(基础):changgou4-common

在这里插入图片描述

  • 通用工具项目

  • 基于spring cloud开发基本依赖

  • web开发常见的工具类

  • 步骤一:修改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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou4-parent-ali</artifactId>
        <groupId>com.czxy.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>changgou4-common</artifactId>

    <dependencies>
        <!--短信-->
        <dependency>
            <groupId>com.aliyuncs</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aliyuncs.dysmsapi</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>


</project>
  • 步骤二:拷贝工具类
    在这里插入图片描述

3.2.3 公共项目(认证):changgou4-common-auth

  • 认证通用工具项目

  • 步骤一:修改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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou4-parent-ali</artifactId>
        <groupId>com.czxy.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>changgou4-common-auth</artifactId>

    <dependencies>
        <!--通用基础-->
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4_common</artifactId>
        </dependency>
        <!--JavaBean工具类,用于JavaBean数据封装-->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
        </dependency>

        <!--jwt工具-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>

        <!--joda 时间工具类 -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>
    </dependencies>


</project>
  • 步骤二:拷贝工具类
    在这里插入图片描述

3.2.4 公共项目(数据库):changgou4-common-db

  • 数据库通用工具项目

  • 步骤一:修改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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou4-parent-ali</artifactId>
        <groupId>com.czxy.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>changgou4-common-db</artifactId>

    <dependencies>
        <!--通用基础-->
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4-common</artifactId>
        </dependency>
        <!-- mybatis plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- druid启动器 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

</project>
  • 步骤二:配置类
  • 要求所有的服务项目包名必须是“com.czxy.changgou4”,否则配置无法扫描,就需要每个项目单独拷贝。

在这里插入图片描述
3.2.5 POJO项目:changgou4-pojo
 统一管理所有的JavaBean

 修改pom.xml文件



org.projectlombok
lombok



org.springframework.boot
spring-boot-starter-json



com.baomidou
mybatis-plus-annotation

3.2.6 网关:changgou4-gateway

  • 修改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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou4-parent-ali</artifactId>
        <groupId>com.czxy.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>changgou4-gateway</artifactId>

    <dependencies>
        <!--自定义项目-->
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4-common-auth</artifactId>
        </dependency>
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4-pojo</artifactId>
        </dependency>
        <!-- 网关 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <!-- nacos 服务发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>


</project>

  • 创建application.yml文档
#端口号
server:
  port: 10010
spring:
  application:
    name: changgou4-gateway
  servlet:
    multipart:
      max-file-size: 2MB    #上传文件的大小
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848   #nacos服务地址
    gateway:
      discovery:
        locator:
          enabled: true               #开启服务注册和发现的功能,自动创建router以服务名开头的请求路径转发到对应的服务
          lowerCaseServiceId: true    #将请求路径上的服务名配置为小写
  • 拷贝跨域配置类 GlobalCorsConfig

在这里插入图片描述

package com.czxy.changgou4.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

 
@Configuration
public class GlobalCorsConfig {

    @Bean
    public WebFilter corsFilter2() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                HttpHeaders requestHeaders = request.getHeaders();
                ServerHttpResponse response = ctx.getResponse();
                HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
                HttpHeaders headers = response.getHeaders();
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
                headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
                        requestHeaders.getAccessControlRequestHeaders());
                if (requestMethod != null) {
                    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
                }
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
                headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }

}
  • 创建启动类
  • 在这里插入图片描述

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

 
@SpringBootApplication
@EnableDiscoveryClient
public class CGGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(CGGatewayApplication.class, args );
    }
}

3.3 前端环境

3.3.1 构建项目:changgou4-fore

  • 步骤一:使用脚手架构建项目
    npx create-nuxt-app changgou4-fore

  • 步骤二:npm打包方式、axios第三方模块、SSR渲染模式

3.3.2 整合axios

  • 步骤一:创建~/plugins/apiclient.js文件
  • 步骤二:编写nuxt整合模板,用于统一管理ajax请求路径
const request = {
  test : ()=> {
    return axios.get('/test')
  }
}

var axios = null
export default ({ $axios, redirect }, inject) => {

  //赋值
  axios = $axios

  //4) 将自定义函数交于nuxt
  // 使用方式1:在vue中,this.$request.xxx()
  // 使用方式2:在nuxt的asyncData中,content.app.$request.xxx()
  inject('request', request)
}
  • 步骤三:配置apiclient.js插件,修改nuxt.conf.js配置文件完成操作
    在这里插入图片描述
  plugins: [
    { src: '~plugins/apiclient.js'}
  ],
  • 步骤四:修改nuxt.conf.js配置文件,配置axios通用设置
    在这里插入图片描述
  axios: {
    baseURL: 'http://localhost:10010'
  },
  • 步骤五:测试 apiclient.js是否配置成功,访问test时,出现404
  async mounted() {
    let { data } = await this.$request.test()
    console.info(data)
  },

3.3.3 拷贝静态资源

  • 将所有静态资源拷贝到static目录中
    在这里插入图片描述
  • 通过浏览器访问静态页面
    在这里插入图片描述

3.3.4 修改Nuxt项目默认项

  • 1 修改默认布局,删除已有样式

在这里插入图片描述

  • 2 删除pages目录下的所有内容
    在这里插入图片描述

3.3.5 配置公共js和css

  • 修改默认布局,添加公共js和css
    在这里插入图片描述
<template>
  <div>
    <nuxt />
  </div>
</template>

<script>
export default {
  head: {
    title: '首页',
    link: [
      {rel:'stylesheet',href: '/style/base.css'},
      {rel:'stylesheet',href: '/style/global.css'},
      {rel:'stylesheet',href: '/style/header.css'},
      {rel:'stylesheet',href: '/style/footer.css'}
    ],
    script: [
      { type: 'text/javascript', src: '/js/jquery-1.8.3.min.js' }
    ]
  }
}
</script>

<style>

</style>

4. 用户模块(8081)

4.1 搭建环境

4.1.1 后端web服务:changgou4-service-web

  • 修改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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou4-parent-ali</artifactId>
        <groupId>com.czxy.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>changgou4_service_web</artifactId>

    <dependencies>
        <!--自定义项目-->
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4_common_db</artifactId>
        </dependency>
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4_pojo</artifactId>
        </dependency>
        <!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- nacos 客户端 -->
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
        </dependency>

        <!-- nacos 服务发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>
    </dependencies>

</project>
  • 创建application.yml文档
    在这里插入图片描述
#端口号
server:
  port: 8081

spring:
  application:
    name: web-service          #服务名
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/changgou_db?useUnicode=true&characterEncoding=utf8
    username: root
    password: 1234
    druid:    #druid 连接池配置
      initial-size: 1       #初始化连接池大小
      min-idle: 1           #最小连接数
      max-active: 20        #最大连接数
      test-on-borrow: true  #获取连接时候验证,会影响性能
  redis:
    database:   0
    host: 127.0.0.1
    port: 6379
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848   #nacos服务地址
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
  • 创建启动类
    在这里插入图片描述
package com.czxy.changgou4;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class Web-serviceApplication {
    public static void main(String[] args) {
        SpringApplication.run( Web-serviceApplication.class , args );
    }
}

4.1.2 后端创建JavaBean:User

  • 在changgou4-pojo项目中添加User对象
    在这里插入图片描述
package com.czxy.changgou4.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.beans.Transient;
import java.util.Date;

/**  与数据库对应JavaBean
 * Created by liangtong.
 */
@TableName("tb_user")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    /*
        CREATE TABLE `tb_user` (
           `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
           `created_at` timestamp NULL DEFAULT NULL,
           `updated_at` timestamp NULL DEFAULT NULL,
           `email` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Email',
           `mobile` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '手机号码',
           `username` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '昵称',
           `password` char(60) COLLATE utf8_unicode_ci NOT NULL COMMENT '密码',
           `face` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '头像',
           `expriece` int(10) unsigned DEFAULT '0' COMMENT '经验值',
           PRIMARY KEY (`id`),
           UNIQUE KEY `users_mobile_unique` (`mobile`),
           UNIQUE KEY `users_name_unique` (`name`),
           UNIQUE KEY `users_email_unique` (`email`)
         ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
     */
    @TableId(value="id",type = IdType.AUTO)
    private Long id;

    @TableField(value="username")
    private String username;

    @TableField(value="password")
    private String password;

    @TableField(value="face")
    private String face;

    @TableField(value="expriece")
    private Integer expriece;

    @TableField(value="email")
    private String email;

    @TableField(value="mobile")
    private String mobile;

    @TableField(value="created_at")
    private Date createdAt;

    @TableField(value="updated_at")
    private Date updatedAt;

    @TableField(exist = false)
    private String code;
    @TableField(exist = false)
    private String password_confirm;

}

4.1.3 前端页面:创建公共组件

  • 1 删除components目录下所有内容,并创建3个新组件

在这里插入图片描述

  • 2)创建 TopNav.vue组件,用于配置“顶部导航”
<template>
  <!-- 顶部导航 start -->
  <div class="topnav">
    <div class="topnav_bd w990 bc">
      <div class="topnav_left">

      </div>
      <div class="topnav_right fr">
        <ul>
          <li>您好,欢迎来到畅购![<a href="login.html">登录</a>] [<a href="register.html">免费注册</a>] </li>
          <li class="line">|</li>
          <li>我的订单</li>
          <li class="line">|</li>
          <li>客户服务</li>

        </ul>
      </div>
    </div>
  </div>
  <!-- 顶部导航 end -->
</template>

<script>
export default {

}
</script>

<style>

</style>
  • 3 创建 HeaderLogo.vue组件,用于配置“页面头部,仅有LOGO”
    在这里插入图片描述
<template>
  <!-- 页面头部 start -->
  <div class="header w990 bc mt15">
    <div class="logo w990">
      <h2 class="fl"><a href="index.html"><img src="/images/logo.png" alt="畅购商城"></a></h2>
    </div>
  </div>
  <!-- 页面头部 end -->
</template>

<script>
export default {

}
</script>

<style>

</style>
  • 4)创建 Footer.vue组件,用于配置“底部版权”
    在这里插入图片描述
<template>
  <!-- 底部版权 start -->
  <div class="footer w1210 bc mt15">
    <p class="links">
      <a href="">关于我们</a> |
      <a href="">联系我们</a> |
      <a href="">人才招聘</a> |
      <a href="">商家入驻</a> |
      <a href="">千寻网</a> |
      <a href="">奢侈品网</a> |
      <a href="">广告服务</a> |
      <a href="">移动终端</a> |
      <a href="">友情链接</a> |
      <a href="">销售联盟</a> |
      <a href="">畅购论坛</a>
    </p>
    <p class="copyright">
       © 2006-2020 畅购网上商城 版权所有,并保留所有权利。  ICP备案证书号:京ICP证070359号
    </p>
    <p class="auth">
      <a href=""><img src="/images/xin.png" alt="" /></a>
      <a href=""><img src="/images/kexin.jpg" alt="" /></a>
      <a href=""><img src="/images/police.jpg" alt="" /></a>
      <a href=""><img src="/images/beian.gif" alt="" /></a>
    </p>
  </div>
  <!-- 底部版权 end -->
</template>

<script>
export default {

}
</script>

<style>

</style>

4.2 用户注册:用户名占用

在这里插入图片描述

4.2.1 接口

http://localhost:10010/web-service/user/checkusername

4.2.2 后端

  • 创建三层需要的接口或类
    在这里插入图片描述
  • 步骤一:创建UserMapper,编写findByUsername()完成“通过用户名查询用户”
package com.czxy.changgou4.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.czxy.changgou4.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

 
@org.apache.ibatis.annotations.Mapper
public interface UserMapper extends BaseMapper<User> {
    /**
     * 通过用户名查询
     * @param username
     * @return
     */
    @Select("select * from tb_user where username = #{username}")
    User findByUsername(@Param("username") String username);
}
  • 步骤二:创建UserService接口,查询功能
package com.czxy.changgou4.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.czxy.changgou4.pojo.User;

public interface UserService extends IService<User> {
    /**
     * 通过用户名查询
     * @param username
     * @return
     */
    public User findByUsername(String username);
}
  • 步骤三:创建UserServiceImpl实现类,查询功能
package com.czxy.changgou4.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.czxy.changgou4.mapper.UserMapper;
import com.czxy.changgou4.pojo.User;
import com.czxy.changgou4.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author zzllforever
 *  
 */
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Override
    public User findByUsername(String username) {
        return baseMapper.findByUsername(username);
    }
}
  • 步骤四:创建UserController,完成用户名检查
package com.czxy.changgou4.controller;

import com.czxy.changgou4.pojo.User;
import com.czxy.changgou4.service.UserService;
import com.czxy.changgou4.vo.BaseResult;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;


/**
 * Created by  .
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;

    @PostMapping("/checkusername")
    public BaseResult checkUsername(@RequestBody User user){
        //查询用户
        User findUser = userService.findByUsername( user.getUsername() );
        //判断
        if(findUser != null){
            return BaseResult.error("用户名已经存在");
        } else {
            return BaseResult.ok("用户名可用");
        }
    }


}

4.2.3 前端

  • 步骤一:创建Register.vue
    在这里插入图片描述
  • 步骤二:添加公共组件
    在这里插入图片描述
<template>
  <div>
    <TopNav></TopNav>
    <div style="clear:both;"></div>
    <HeaderLogo></HeaderLogo>
    <div style="clear:both;"></div>
    <!-- 正文 -->
    <div style="clear:both;"></div>
    <Footer></Footer>
  </div>
</template>

<script>
import TopNav from '../components/TopNav'
import HeaderLogo from '../components/HeaderLogo'
import Footer from '../components/Footer'
export default {
  head: {
    title: '用户注册'
  },
  components : {
    TopNav,
    HeaderLogo,
    Footer
  }
}
</script>

<style>

</style>

  • 步骤三:编写注册表单,并导入独有样式
<template>
  <div>
    <TopNav></TopNav>
    <div style="clear:both;"></div>
    <HeaderLogo></HeaderLogo>
    <div style="clear:both;"></div>
    <!-- 正文 -->
      <!-- 登录主体部分start -->
  <div class="login w990 bc mt10 regist">
    <div class="login_hd">
      <h2>用户注册</h2>
      <b></b>
    </div>
    <div class="login_bd">
      <div class="login_form fl">
        <form action="" method="post">
          <ul>
            <li>
              <label for="">用户名:</label>
              <input type="text" class="txt" name="username" />
              <p>3-20位字符,可由中文、字母、数字和下划线组成</p>
              <p class="error">用户名已存在</p>
            </li>
            <li>
              <label for="">密码:</label>
              <input type="password" class="txt" name="password" />
              <p>6-20位字符,可使用字母、数字和符号的组合,不建议使用纯数字、纯字母、纯符号</p>
            </li>
            <li>
              <label for="">确认密码:</label>
              <input type="password" class="txt" name="password" />
              <p>请再次输入密码</p>
            </li>
            <li>
              <label for="">手机号码:</label>
              <input type="text" class="txt"  name="mobile" />
              <p>请输入手机号码</p>
            </li>
            <li class="checkcode">
              <label for="">验证码:</label>
              <input type="text"  name="checkcode" />
              <button >
                发送验证码<span>5秒</span>
              </button>
            </li>
            <li>
              <label for="">&nbsp;</label>
              <input type="checkbox" class="chb" checked="checked" /> 我已阅读并同意《用户注册协议》
            </li>
            <li>
              <label for="">&nbsp;</label>
              <input type="submit" value="" class="login_btn" />
            </li>
          </ul>
        </form>
      </div>
      <div class="mobile fl">
        <h3>手机快速注册</h3>
        <p>中国大陆手机用户,编辑短信 “<strong>XX</strong>”发送到:</p>
        <p><strong>1069099988</strong></p>
      </div>

    </div>
  </div>
  <!-- 登录主体部分end -->
    <div style="clear:both;"></div>
    <Footer></Footer>
  </div>
</template>

<script>
import TopNav from '../components/TopNav'
import HeaderLogo from '../components/HeaderLogo'
import Footer from '../components/Footer'
export default {
  head: {
    title: '用户注册',
    link: [
      {rel:'stylesheet',href:'style/login.css'}
    ],
    script: [
      { type: 'text/javascript', src: 'js/header.js' },
      { type: 'text/javascript', src: 'js/index.js' },
    ]
  },
  components : {
    TopNav,
    HeaderLogo,
    Footer
  }
}
</script>

<style>

</style>
  • 步骤四:修改api.js,编写检查用户名的ajax函数
const request = {
  test : ()=> {
    return axios.get('/test')
  },
  //检查用户名
  checkUsername : ( username )=> {
    return axios.post('/web-service/user/checkusername', { username })
  }
}

  • 步骤五:修改Register.vue页面,完成检查功能
  • 发送ajax进行用户名是否可用检查
  • 如果可用,显示对应信息,并使用success样式显示
  • 如果不可用,显示对应信息,并使用error样式提示
<template>
  <div>
    <TopNav></TopNav>
    <div style="clear:both;"></div>
    <HeaderLogo></HeaderLogo>
    <div style="clear:both;"></div>
    <!-- 正文 -->
      <!-- 登录主体部分start -->
  <div class="login w990 bc mt10 regist">
    <div class="login_hd">
      <h2>用户注册</h2>
      <b></b>
    </div>
    <div class="login_bd">
      <div class="login_form fl">
        <form action="" method="post">
          <ul>
            <li>
              <label for="">用户名:</label>
              <input type="text" class="txt" name="username" v-model="user.username" @blur="checkUsernameFn" />
              <p>3-20位字符,可由中文、字母、数字和下划线组成</p>
              <p :class="userMsg.usernameData.code == 1 ? 'success' : 'error'">{{userMsg.usernameData.message}} </p>
            </li>
            <li>
              <label for="">密码:</label>
              <input type="password" class="txt" name="password" />
              <p>6-20位字符,可使用字母、数字和符号的组合,不建议使用纯数字、纯字母、纯符号</p>
            </li>
            <li>
              <label for="">确认密码:</label>
              <input type="password" class="txt" name="password" />
              <p>请再次输入密码</p>
            </li>
            <li>
              <label for="">手机号码:</label>
              <input type="text" class="txt"  name="mobile" />
              <p>请输入手机号码</p>
            </li>
            <li class="checkcode">
              <label for="">验证码:</label>
              <input type="text"  name="checkcode" />
              <button >
                发送验证码<span>5秒</span>
              </button>
            </li>
            <li>
              <label for="">&nbsp;</label>
              <input type="checkbox" class="chb" checked="checked" /> 我已阅读并同意《用户注册协议》
            </li>
            <li>
              <label for="">&nbsp;</label>
              <input type="submit" value="" class="login_btn" />
            </li>
          </ul>
        </form>
      </div>
      <div class="mobile fl">
        <h3>手机快速注册</h3>
        <p>中国大陆手机用户,编辑短信 “<strong>XX</strong>”发送到:</p>
        <p><strong>1069099988</strong></p>
      </div>

    </div>
  </div>
  <!-- 登录主体部分end -->
    <div style="clear:both;"></div>
    <Footer></Footer>
  </div>
</template>

<script>
import TopNav from '../components/TopNav'
import HeaderLogo from '../components/HeaderLogo'
import Footer from '../components/Footer'
export default {
  head: {
    title: '用户注册',
    link: [
      {rel:'stylesheet',href:'style/login.css'}
    ],
    script: [
      { type: 'text/javascript', src: 'js/header.js' },
      { type: 'text/javascript', src: 'js/index.js' },
    ]
  },
  components : {
    TopNav,
    HeaderLogo,
    Footer
  },
  data() {
    return {
      user : {			//表单绑定对象
        username : ""
      },
      userMsg : {		//错误信息
        usernameData : ""
      }
    }
  },
  methods: {
    async checkUsernameFn() {
      let {data} = await this.$request.checkUsername( this.user.username )
      this.userMsg.usernameData = data
    }
  },
}
</script>

<style>

</style>

4.3 用户注册:手机号检查

4.3.1 接口

http://localhost:10010/web-service/user/checkmobile
4.3.2 后端

  • 步骤一:修改UserService,添加 findByMobile() 方法,进行电话号码的查询
/**
 * 通过手机号查询
 * @param mobile
 * @return
 */
User findByMobile(String mobile);

	步骤二:编写UserServiceImpl,实现findByMobile() 方法
@Override
public User findByMobile(String mobile) {
    // 拼凑条件
    QueryWrapper queryWrapper = new QueryWrapper();
    queryWrapper.eq("mobile", mobile);
    // 查询一个
    List<User> list = baseMapper.selectList(queryWrapper);
    if(list.size() == 1) {
        return list.get(0);
    }
    return null;
}

	步骤三:修改UserController,添加checkMobile() 方法
/**
 * 通过手机号查询
 * @param user
 * @return
 */
@PostMapping("/checkmobile")
public BaseResult checkMobile(@RequestBody User user){
    //查询用户
    User findUser = userService.findByMobile( user.getMobile() );
    //判断
    if(findUser != null){
        return BaseResult.error("电话号码已经注册");
    } else {
        return BaseResult.ok("电话号码可用");
    }
}

4.3.3 前端

  • 步骤一:修改api.js,添加 checkMobile() 函数

const request = {
  test : ()=> {
    return axios.get('/test')
  },
  //检查用户名
  checkUsername : ( username )=> {
    return axios.post('/web-service/user/checkusername', { username })
  },
  //检查电话号码
  checkMobile : ( mobile )=> {
    return axios.post('/web-service/user/checkmobile', { mobile })
  }
}
  • 步骤二:修改Register.vue,添加 checkMobileFn() 进行手机号检查
  methods: {
    async checkUsernameFn() {
      //检查用户名
      let {data} = await this.$request.checkUsername( this.user.username )
      this.userMsg.usernameData = data
    },
    async checkMobileFn() {
      //检查电话
      let {data} = await this.$request.checkMobile( this.user.mobile )
      this.userMsg.mobileData = data
    }
  },
  • 步骤三:编写需要的2个变量
  data() {
    return {
      user : {  //表单封装数据
        username : "",
        mobile : ""
      },
      userMsg : { //错误提示数据
        usernameData : "",
        mobileData : ""
      }
    }
  },
  • 步骤四:处理页面
<li>
              <label for="">手机号码:</label>
              <input type="text" class="txt"  name="mobile"  v-model="user.mobile" @blur="checkMobileFn" />
              <p>请输入手机号码</p>
              <p :class="userMsg.mobileData.code == 1 ? 'success' : 'error'">{{userMsg.mobileData.message}} </p>
            </li>
            ~~~


*	完整版

~~~vue
<template>
  <div>
    <TopNav></TopNav>
    <div style="clear:both;"></div>
    <HeaderLogo></HeaderLogo>
    <div style="clear:both;"></div>
    <!-- 正文 -->
      <!-- 登录主体部分start -->
  <div class="login w990 bc mt10 regist">
    <div class="login_hd">
      <h2>用户注册</h2>
      <b></b>
    </div>
    <div class="login_bd">
      <div class="login_form fl">
        <form action="" method="post">
          <ul>
            <li>
              <label for="">用户名:</label>
              <input type="text" class="txt" name="username" v-model="user.username" @blur="checkUsernameFn" />
              <p>3-20位字符,可由中文、字母、数字和下划线组成</p>
              <p :class="userMsg.usernameData.code == 1 ? 'success' : 'error'">{{userMsg.usernameData.message}} </p>
            </li>
            <li>
              <label for="">密码:</label>
              <input type="password" class="txt" name="password" />
              <p>6-20位字符,可使用字母、数字和符号的组合,不建议使用纯数字、纯字母、纯符号</p>
            </li>
            <li>
              <label for="">确认密码:</label>
              <input type="password" class="txt" name="password" />
              <p>请再次输入密码</p>
            </li>
            <li>
              <label for="">手机号码:</label>
              <input type="text" class="txt"  name="mobile"  v-model="user.mobile" @blur="checkMobileFn" />
              <p>请输入手机号码</p>
              <p :class="userMsg.mobileData.code == 1 ? 'success' : 'error'">{{userMsg.mobileData.message}} </p>
            </li>
            <li class="checkcode">
              <label for="">验证码:</label>
              <input type="text"  name="checkcode" />
              <button >
                发送验证码<span>5秒</span>
              </button>
            </li>
            <li>
              <label for="">&nbsp;</label>
              <input type="checkbox" class="chb" checked="checked" /> 我已阅读并同意《用户注册协议》
            </li>
            <li>
              <label for="">&nbsp;</label>
              <input type="submit" value="" class="login_btn" />
            </li>
          </ul>
        </form>
      </div>
      <div class="mobile fl">
        <h3>手机快速注册</h3>
        <p>中国大陆手机用户,编辑短信 “<strong>XX</strong>”发送到:</p>
        <p><strong>1069099988</strong></p>
      </div>

    </div>
  </div>
  <!-- 登录主体部分end -->
    <div style="clear:both;"></div>
    <Footer></Footer>
  </div>
</template>

<script>
import TopNav from '../components/TopNav'
import HeaderLogo from '../components/HeaderLogo'
import Footer from '../components/Footer'
export default {
  head: {
    title: '用户注册',
    link: [
      {rel:'stylesheet',href:'style/login.css'}
    ],
    script: [
      { type: 'text/javascript', src: 'js/header.js' },
      { type: 'text/javascript', src: 'js/index.js' },
    ]
  },
  components : {
    TopNav,
    HeaderLogo,
    Footer
  },
  data() {
    return {
      user : {  //表单封装数据
        username : "",
        mobile : "",
        password : "",
        code : ""
      },
      userMsg : { //错误提示数据
        usernameData : "",
        mobileData : ""
      }
    }
  },
  methods: {
    async checkUsernameFn() {
      //检查用户名
      let {data} = await this.$request.checkUsername( this.user.username )
      this.userMsg.usernameData = data
    },
    async checkMobileFn() {
      //检查电话
      let {data} = await this.$request.checkMobile( this.user.mobile )
      this.userMsg.mobileData = data
    }
  },
}
</script>

<style>

</style>


4.4 用户注册:前置技术–Redis

4.5 用户注册:前置技术–阿里大鱼

以往写过短信注册:

https://editor.youkuaiyun.com/md/?articleId=121686836

详情就不过赘述

4.6 用户注册:短信验证码

4.6.1 分析

在这里插入图片描述

4.6.2 接口

http://localhost:10010/web-service/sms
{
	"mobile":"13344445555",
	"username": "jack"
}

4.6.3 后端

  • 创建 SmsController类,调用阿里大鱼工具类,发送短信。
    在这里插入图片描述
package com.czxy.changgou4.controller;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.czxy.changgou4.pojo.User;
import com.czxy.changgou4.utils.SmsUtil;
import com.czxy.changgou4.vo.BaseResult;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * Created by   .
 */
@RestController
@RequestMapping("/sms")
public class SmsController {

    @Resource
    private StringRedisTemplate redisTemplate;

    @PostMapping
    public BaseResult sendSms(@RequestBody User user){
        long start = System.currentTimeMillis();
        try {
            //发送短信
            //1 生产验证码
            String code = RandomStringUtils.randomNumeric(4);
            System.out.println("验证码:" + code);

            //2 并存放到reids中 , key: "sms_register" + 手机号 , value:验证码 , 1小时
            redisTemplate.opsForValue().set( "sms_register" + user.getMobile() , code , 1 , TimeUnit.HOURS);

            /**/
            //3 发送短信
            SendSmsResponse smsResponse = SmsUtil.sendSms(user.getMobile(), user.getUsername() , code, "", "");

            //https://help.aliyun.com/document_detail/55284.html?spm=5176.doc55322.6.557.KvvIJx
            if("OK".equalsIgnoreCase(smsResponse.getCode())){
                return BaseResult.ok("发送成功");
            } else {
                return BaseResult.error(smsResponse.getMessage());
            }

            /*
            //模拟数据
            System.out.println("验证码:" + code);
            return BaseResult.ok("发送成功");
            */
        } catch (Exception e) {
            long end = System.currentTimeMillis();
            System.out.println( end - start);
            return BaseResult.error("发送失败" );
        }


    }
}

4.6.4 前端

  • 步骤一:修改apiclient.js,发送短信ajax操作
  //发短信
  sendSms : ( user )=> {
    return axios.post('/web-service/sms', user )
  }
  • 步骤二:修改Register.vue页面,给“发送验证码”绑定点击事件
sendSmsFn
<button  @click.prevent="sendSmsFn" >
                发送验证码<span>5</span>
              </button>

在这里插入图片描述

  • 步骤三:修改Register.vue页面,编写sendSmsFn函数,建议采用 ajax…then()…catch 可以处理异常
sendSmsFn () {
      this.$request.sendSms( this.user )
      .then(( response )=>{
        //发送短信的提示信息
        this.userMsg.smsData = response.data
      })
      .catch(( error )=>{
        //错误提示信息
        alert( error.message )
      })
    }
  • 步骤四:修改Register.vue页面,提供变量smsData
userMsg : { //错误提示数据
        usernameData : "",
        mobileData : "",
        smsData : ""
      }

在这里插入图片描述

  • 步骤五:修改Register.vue页面,显示 smsData提示信息
    在这里插入图片描述

4.6.5 倒计时

  • 步骤一:提供3个变量,用于控制倒计时
    在这里插入图片描述

btnDisabled : false, //倒计时控制变量
seconds : 5, //默认倒计时秒数
timer : null, //接收定时器,清除定时器

  • 步骤二:在标签上面控制倒计时的显示

<button :disabled=“btnDisabled” @click.prevent=“sendSmsFn” >
发送验证码{{seconds}}秒

在这里插入图片描述
在这里插入图片描述

  • 步骤三:发送短信后,开启倒计时控制
sendSmsFn () {
      this.$request.sendSms( this.user )
      .then(( response )=>{
        //发送短信的提示信息
        this.userMsg.smsData = response.data
        //按钮不可用
        this.btnDisabled = true;
          //倒计时
          this.timer = setInterval( ()=>{
            if(this.seconds <= 1){
              //结束
              // 重置秒数
              this.seconds = 5;
              // 按钮可用
              this.btnDisabled = false;
              // 停止定时器
              clearInterval(this.timer);
            } else {
              this.seconds --;
            }
          } , 1000);
      })
      .catch(( error )=>{
        //错误提示信息
        alert( error.message )
      })
    }

4.7 用户注册

4.7.1 接口

http://localhost:10010/web-service/user/register
{
“mobile”:“13612345677”,
“password”:“1234”,
“username”:“jack3”,
“code”:“3919”
}

4.7.2 后端

  • 保存前需要再次进行服务端校验
  • 用户名是否注册
  • 手机号是否注册
  • 验证码是否失效
  • 验证码是否错误
  • 密码需要使用 BCrypt进行加密

*步骤一:修改UserService接口,添加register方法

/**
 * 用户注册
 * @param user
 * @return
 */
public boolean register(User user) ;

步骤二:完善UserServiceImpl实现类

@Override
public boolean register(User user) {
    //密码加密
    String newPassword = BCrypt.hashpw(user.getPassword());
    user.setPassword(newPassword);

    //处理数据
    user.setCreatedAt(new Date());
    user.setUpdatedAt(user.getCreatedAt());

    int insert = baseMapper.insert(user);

    return insert == 1;
}
  • 步骤三:修改UserController,添加register方法
/**
 * 用户注册
 * @param user
 * @return
 */
@PostMapping("/register")
public BaseResult  register(@RequestBody User user){

    //服务端校验
    User findUser = userService.findByUsername(user.getUsername());
    if(findUser != null) {
        return BaseResult.error("用户名已经存在");
    }

    findUser = userService.findByMobile(user.getMobile());
    if(findUser != null) {
        return BaseResult.error("电话号码已经存在");
    }

    //验证码
    String code = stringRedisTemplate.opsForValue().get("sms_register" + user.getMobile());
    //删除redis中的验证码
    stringRedisTemplate.delete("sms_register" + user.getMobile());
    if(code == null) {
        return BaseResult.error("验证码失效");
    }
    if(!code.equals(user.getCode())) {
        return BaseResult.error("验证码不正确");
    }

    //注册
    boolean register = userService.register(user);

    if(register) {
        return BaseResult.ok("注册成功");
    }
    return BaseResult.error("注册失败");
}

4.7.3 日期处理(可选)

  • 编写 DateMetaObjectHandler 用于处理“创建时间”和“修改日期”
package com.czxy.changgou4.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author zzllforever
 * @email 2752776684.com
 */
@Component
public class DateMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createdAt", new Date(), metaObject);
        this.setFieldValByName("updatedAt", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updatedAt", new Date(), metaObject);
    }
}
  • 完善User JavaBean,设置填充方式
@TableField(value="created_at",fill = FieldFill.INSERT)
private Date createdAt;

@TableField(value="updated_at",fill = FieldFill.INSERT_UPDATE)
private Date updatedAt;

4.7.4 前端

  • 步骤一:修改 api.js ,添加注册函数
  //注册
  register : ( user )=> {
    return axios.post('/web-service/user/register', user )
  }
  • 步骤二:处理表单,验证码input绑定数据,提交按钮绑定事件

          <li class="checkcode">
            <label for="">验证码:</label>
            <input type="text"  name="checkcode"  v-model="user.code" />
            <button  :disabled="btnDisabled" @click.prevent="sendSmsFn" >
              发送验证码<span v-show="btnDisabled">{{seconds}}秒</span>
            </button>
            <p :class="userMsg.smsData.code == 1 ? 'success' : 'error'">{{userMsg.smsData.message}} </p>
          </li>
          <li>
            <label for="">&nbsp;</label>
            <input type="checkbox" class="chb" checked="checked" /> 我已阅读并同意《用户注册协议》
          </li>
          <li>
            <label for="">&nbsp;</label>
            <input type="submit" value="" @click.prevent="registerFn" class="login_btn" />
          </li>
    
  • 步骤三:完善data区域的user数据

在这里插入图片描述

user : { //表单封装数据
username : “”, //用户名
mobile : “13699282444”, //手机号
password : “”, //密码
code : “” //验证码
},

  • 步骤四:编写registerFn函数

async registerFn() {
let { data } = await this.KaTeX parse error: Expected '}', got 'EOF' at end of input: …功 this.router.push(’/login’)
} else {
//失败–与发送验证码使用一个位置显示错误信息
this.userMsg.smsData = data
}
}

4.8 用户登录

4.8.1 构建页面:Login.vue

  • 步骤一:创建Login.vue
    在这里插入图片描述
  • 步骤二:绘制通用模块
<template>
  <div>
    <TopNav></TopNav>
    <div style="clear:both;"></div>
    <HeaderLogo></HeaderLogo>
    <div style="clear:both;"></div>
    <!-- 正文 -->
    
    <div style="clear:both;"></div>
    <Footer></Footer>
  </div>
</template>

<script>
import TopNav from '../components/TopNav'
import HeaderLogo from '../components/HeaderLogo'
import Footer from '../components/Footer'
export default {
  head: {
    title: '用户登录',
    link: [
      {rel:'stylesheet',href:'style/login.css'}
    ],
    script: [
    ]
  },
  components : {
    TopNav,
    HeaderLogo,
    Footer
  },

}
</script>

<style>

</style>
  • 步骤三:绘制登录表单
<template>
  <div>
    <TopNav></TopNav>
    <div style="clear:both;"></div>
    <HeaderLogo></HeaderLogo>
    <div style="clear:both;"></div>
    <!-- 正文 -->
    <!-- 登录主体部分start -->
    <div class="login w990 bc mt10">
      <div class="login_hd">
        <h2>用户登录</h2>
        <b></b>
      </div>
      <div class="login_bd">
        <div class="login_form fl">
          <form action="" method="post">
            <ul>
              <li>
                <label for="">用户名:</label>
                <input type="text" class="txt" name="username" />
              </li>
              <li>
                <label for="">密码:</label>
                <input type="password" class="txt" name="password" />
                <a href="">忘记密码?</a>
              </li>
              <li class="checkcode">
                <label for="">验证码:</label>
                <input type="text"  name="checkcode" />
                <img src="images/checkcode1.jpg" alt="" />
                <span>看不清?<a href="">换一张</a></span>
              </li>
              <li>
                <label for="">&nbsp;</label>
                <input type="checkbox" class="chb"  /> 保存登录信息
              </li>
              <li>
                <label for="">&nbsp;</label>
                <input type="submit" value="" class="login_btn" />
              </li>
            </ul>
          </form>

          <div class="coagent mt15">
            <dl>
              <dt>使用合作网站登录商城:</dt>
              <dd class="qq"><a href=""><span></span>QQ</a></dd>
              <dd class="weibo"><a href=""><span></span>新浪微博</a></dd>
              <dd class="yi"><a href=""><span></span>网易</a></dd>
              <dd class="renren"><a href=""><span></span>人人</a></dd>
              <dd class="qihu"><a href=""><span></span>奇虎360</a></dd>
              <dd class=""><a href=""><span></span>百度</a></dd>
              <dd class="douban"><a href=""><span></span>豆瓣</a></dd>
            </dl>
          </div>
        </div>

        <div class="guide fl">
          <h3>还不是商城用户</h3>
          <p>现在免费注册成为商城用户,便能立刻享受便宜又放心的购物乐趣,心动不如行动,赶紧加入吧!</p>

          <a href="regist.html" class="reg_btn">免费注册 >></a>
        </div>

      </div>
    </div>
    <!-- 登录主体部分end -->
    <div style="clear:both;"></div>
    <Footer></Footer>
  </div>
</template>

<script>
import TopNav from '../components/TopNav'
import HeaderLogo from '../components/HeaderLogo'
import Footer from '../components/Footer'
export default {
  head: {
    title: '用户登录',
    link: [
      {rel:'stylesheet',href:'style/login.css'}
    ],
    script: [
    ]
  },
  components : {
    TopNav,
    HeaderLogo,
    Footer
  },

}
</script>

<style>

</style>

4.8.2 分析

在这里插入图片描述

4.8.3 验证码:接口

http://localhost:10010/web-service/verifycode?username=jack

4.8.4 验证码:生成与显示

  • 步骤一:后端生产验证码,并将用户保存Redis
  • 存放redis中验证码key格式:“login” + 用户名
package com.czxy.changgou4.controller;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author zzllforever
 * @email 2752776684.com
 */
@Controller
@RequestMapping("/verifycode")
public class VerifyCodeController {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping
    public void verifyCode(String username , HttpServletResponse response ) throws IOException {

        //字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
        String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";

        int IMG_WIDTH = 72;
        int IMG_HEIGTH = 27;
        Random random = new Random();
        //创建图片
        BufferedImage image = new BufferedImage(IMG_WIDTH, IMG_HEIGTH, BufferedImage.TYPE_INT_RGB);
        //画板
        Graphics g = image.getGraphics();
        //填充背景
        g.setColor(Color.WHITE);
        g.fillRect(1,1,IMG_WIDTH-2,IMG_HEIGTH-2);

        g.setFont(new Font("楷体", Font.BOLD,25));

        StringBuilder sb = new StringBuilder();
        //写字
        for(int i = 1 ; i <= 4 ; i ++){
            //随机颜色
            g.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
            int len = random.nextInt(VERIFY_CODES.length());
            String str = VERIFY_CODES.substring(len,len+1);
            sb.append(str);
            g.drawString(str, IMG_WIDTH / 6 * i , 22 );
        }

        //将验证码存放到redis
        stringRedisTemplate.opsForValue().set( "login" + username , sb.toString() , 1 , TimeUnit.HOURS);


        // 生成随机干扰线
        for (int i = 0; i < 30; i++) {
            //随机颜色
            g.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
            int x = random.nextInt(IMG_WIDTH - 1);
            int y = random.nextInt(IMG_HEIGTH - 1);
            int x1 = random.nextInt(12) + 1;
            int y1 = random.nextInt(6) + 1;
            g.drawLine(x, y, x - x1, y - y1);
        }

        //响应到浏览器
        ImageIO.write(image,"jpeg", response.getOutputStream());

    }
}
  • 步骤二:点击“换一张”显示验证码
  • 默认不显示验证码
  • 点击“换一张”获得验证码

在这里插入图片描述

<template>
  <div>
    <TopNav></TopNav>
    <div style="clear:both;"></div>
    <HeaderLogo></HeaderLogo>
    <div style="clear:both;"></div>
    <!-- 正文 -->
    <!-- 登录主体部分start -->
    <div class="login w990 bc mt10">
      <div class="login_hd">
        <h2>用户登录</h2>
        <b></b>
      </div>
      <div class="login_bd">
        <div class="login_form fl">
          <form action="" method="post">
            <ul>
              <li>
                <label for="">用户名:</label>
                <input type="text" class="txt" name="username" v-model="user.username" />
              </li>
              <li>
                <label for="">密码:</label>
                <input type="password" class="txt" name="password" v-model="user.password" />
                <a href="">忘记密码?</a>
              </li>
              <li class="checkcode">
                <label for="">验证码:</label>
                <input type="text"  name="checkcode" />
                <!-- <img src="images/checkcode1.jpg" alt="" /> -->
                <img :src="imgSrc" alt="" />
                <span>看不清?<a href="" @click.prevent="changeVerifyCode">换一张</a></span>
              </li>
              <li v-if="errorMsg != ''">
                <label for="">&nbsp;</label>
                <span style="color: #ff5b5b">{{errorMsg}}</span>
              </li>
              <li>
                <label for="">&nbsp;</label>
                <input type="checkbox" class="chb"  /> 保存登录信息
              </li>
              <li>
                <label for="">&nbsp;</label>
                <input type="submit" value="" class="login_btn" />
              </li>
            </ul>
          </form>

          <div class="coagent mt15">
            <dl>
              <dt>使用合作网站登录商城:</dt>
              <dd class="qq"><a href=""><span></span>QQ</a></dd>
              <dd class="weibo"><a href=""><span></span>新浪微博</a></dd>
              <dd class="yi"><a href=""><span></span>网易</a></dd>
              <dd class="renren"><a href=""><span></span>人人</a></dd>
              <dd class="qihu"><a href=""><span></span>奇虎360</a></dd>
              <dd class=""><a href=""><span></span>百度</a></dd>
              <dd class="douban"><a href=""><span></span>豆瓣</a></dd>
            </dl>
          </div>
        </div>

        <div class="guide fl">
          <h3>还不是商城用户</h3>
          <p>现在免费注册成为商城用户,便能立刻享受便宜又放心的购物乐趣,心动不如行动,赶紧加入吧!</p>

          <a href="regist.html" class="reg_btn">免费注册 >></a>
        </div>

      </div>
    </div>
    <!-- 登录主体部分end -->
    <div style="clear:both;"></div>
    <Footer></Footer>
  </div>
</template>

<script>
import TopNav from '../components/TopNav'
import HeaderLogo from '../components/HeaderLogo'
import Footer from '../components/Footer'
export default {
  head: {
    title: '用户登录',
    link: [
      {rel:'stylesheet',href:'style/login.css'}
    ],
    script: [
    ]
  },
  components : {
    TopNav,
    HeaderLogo,
    Footer
  },
  data() {
    return {
      imgSrc:'',
      errorMsg: '',
      user: {

      }
    }
  },
  methods: {
    changeVerifyCode() {
      if( this.user.username ) {
        this.imgSrc = `http://localhost:10010/web-service/verifycode?t=${new Date().getTime()}&username=${this.user.username }`
      } else {
        this.errorMsg = '用户名不能为空'
      }
    }
  },
  watch: {
    'user' : {
      handler(v) {
        if(v) {
          //如果user数据发生改变,修改提示信息
          this.errorMsg = ''
        }
      },
      deep: true
    }
  },

}
</script>

<style>

</style>

4.8.5 通过用户名查询:接口

http://localhost:10010/web-service/user/findByUsername {
“username”:“jack” }

C#,读做 "C sharp",中文译音暂时没有,非专业人士一般读"C井",专业人士一般读"C sharp"。   C#是一种安全的、稳定的、简单的、优雅的,由C和C++衍生出来的面向对象的编程语言。它在继承C和C++强大功能的同时去掉了一些它们的复杂特性(例如没有宏和模版,不允许多重继承)。C#综合了VB简单的可视化操作和C++的高运行效率,以其强大的操作能力、优雅的语法风格、创新的语言特性和便捷的面向组件编程的支持成为.NET开发的首选语言。 C# 并且C#成为ECMA与ISO标准规范。C#看似基于C++写成,但又融入其它语言如Pascal、Java、VB等。   微软c#语言定义主要是从C和C++继承而来的,而且语言中的许多元素也反映了这一点.C#在设计者从C++继承的可选选项方面比Java要广泛一些(比如说struts),它还增加了自己新的特点(比方说源代码版本定义).但它还太不成熟,不可能挤垮Java.C#还需要进化成一种开发者能够接受和采用的语言.而微软当前为它的这种新语言大造声势也是值得注意的.目前大家的反应是:"这是对Java的反击."   C#更像Java一些,虽然微软在这个问题上保持沉默.这也是意料中的事情,我觉得,因为Java近来很成功而使用Java的公司都报告说它们在生产效率上比C++获得了提高.   Java所带来的巨大影响和大家对它的广泛接受已经由工作于这种语言和平台之上的程序员数量明显的说明了(估计世界范围内共有两百五十万程序员使用Java).由这种语言写成的应用程序的数量是令人惊讶的并已经渗透了每一个级别的计算,包括无线计算和移动电话(比如日本发明的Java电话).C#能够在用户领域获得这样的礼遇吗?我们必须等待并观望,就像已经由SSI公司的CEO和主席Kalpathi S. Suresh指出来的那样,"我发现所有这些都是渐进的.如果C#不存在,我们总能回到Java或C和C++.这些都不完全是新技术;它们在更大的意义上来说只是大公司制造的市场噱头.我们必须给他们时间安顿下来看看这些是不是真的对IT工业有什么影响."
商 品 交 易 管 理 系 统 【摘要】本文简要介绍了本商品管理系统的开发情况,基本设计思想、系统开发环境及目前的应用情况。 关键词 订单 代理商 销售查询 备份 目 录: 第一章 引言 第二章 数据库应用系统开发简介 2.1 数据库 2.2 数据库管理系统 2.3 创建数据库 第三章 应用系统开发工具 3.1 DELPHI简介 3.2 DELPHI数据库访问方法与数据库组件介绍 第四章 商品销售管理系统目标分析 4.1 任务分析 4.2 系统目标 第五章 商品销售管理系统的数据库设计 5.1 常见应用程序数据表 5.2 DELPHI中的数据文件路径管理 第六章 试题库系统应用程序界面设计 6.1 用户登录窗体 6.2 主窗体 6.3 系统设置窗体 6.4 权限管理窗体 6.5 操作员信息设置窗体 6.6 代理商进/退货录入窗口 6.7 订单进货数据录入窗口 6.8 代理商销售数据查询窗口 6.9 商品分布查询窗口 第七章 结束语 致谢 主要参考文献 附录程序清单及注释 一 引 言 随着大学教学改革进一步的深入和大学本科课程建设的逐步完善,对学生掌握每一课程内容程度的考试必须规范化,系统化,科学化,现代化;教学管理必须现代化、规范化。我们知道,传统的出试卷方法是由教师个人组卷,这样往往造成试题难度和知识覆盖面难以把握,不能达到对学生的科学而又全面的考核。针对这一情况,我们研制了计算机类学科试题库与自动组卷系统。一方面,自动组卷系统避免了手工出试卷造成的试卷不规范,不易集中管理;另一方面,避免教师每次考试时手工组卷及平时为学生组织练习时的重复劳动,将教师从简单、重复的环节中解脱出来,以更多的精力投入到教学与科研中去。 高校教务管理工作中一项非常重要的工作就是考试管理工作,每学期各专业考试,从组织出卷到试卷的印制及试卷的管理等工作非常繁琐且工作量很大,这种组织管理方式不仅工作任务繁重而且试卷的标准化程度、难易程度、题量大小等各方面难以控制,难以形成有效的试题库,不利于充分发挥历年来的优秀试题及试卷的作用,给试题和试卷的管理带来很多问题和困难。鉴于这种情况,利用计算机进行试卷的自动生成并逐步积累形成有效的试题库,对试题和试卷的管理将变的高效而便捷,对提高工作效率,使试卷管理逐步走向正规化自动化将起到十分重要的作用。 在试题库的制作方面,通过自动组卷系统对每次考试的实现,可以不断地对试题库的内容进行完善。在每一次组卷时,可以进一步对每题的内容进行分析,发现细微的问题,对试题库的内容作进一步地修改。这样避免了传统出试卷时,考试一次结束一次的缺点。由于试题库的建设具有继承性,规范性,可以不断积累考试经验,丰富试题库的内容。 二 数据库应用系统开发简介 在数据库应用系统开发之前,对开发数据库的基本概念应当了解,对数据库的结构、开发数据库应用程序的步骤、开发体系及方法都应当有相当清晰的了解和认识。 数据库应用系统开发的目标是建立一个满足用户长期需求的产品。开发的主要过程为:理解用户的需求,然后,把它们转变为有效的数据库设计。把设计转变为实际的数据库,并且这些数据库带有功能完备、高效能的应用。 数据库技术在计算机软件邻域研究中一直是非常重要的主题,产生于60年代,30多年来数据库技术得到了迅速发展,并已形成较为完整的理论体系和一大批实用系统。并且,近年来,随着World Wide Web(WWW)的猛增及Internet技术的迅速发展,使得数据库技术之时成为最热门技术之一。 §2.1 数据库 数据库由DBMS(数据库管理系统)处理,DBMS则由开发人员和用户通过应用程序直接或间接地使用。它主要包括四个要素:用户数据、元数据、索引和应用元数据。 用户数据: 目前,大多数主流数据库管理系统把用户数据表示为关系。现在把关系看作数据表。表的列包含域或属性,表的行包含对应业务环境中的实体的记录。并非所有的关系都同样符合要求,有些关系比其它关系更结构化一些。 元数据: 数据库是自描述的,这就意味着它自身包含了它的结构的描述,这种结构的描述称作元数据。因为DBMS产品是用来存储和操纵表的,所以大多数产品把元数据以表的形式存储,有时称作系统表。这些系统表存储了数据库中表的情况,指出每一个表中有多少列,那一列是主关键字,每一列的数据类型的描述,它也存储索引、关键字、规则和数据库结构的其他部分。在表中存储元数据不仅对DBMS是有效的,对用户也是方便的,因为他们可以使用与查询用户数据同样的查询工具来查询元数据。本文介绍的SQL语言可以同时用于元数据和用户数据。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值