12306项目随手笔记5

前段代码大都来自这个大佬,写的都很详细,建议看他的NEIL_XU_-CSDN博客

后续再来改好点

5.1-5.3

 准备环境vue cli安装(前段搭建脚手架)

需要安装node.js

安装node.js----修改环境变量----配置镜像

安装vue cli

执行命令(不知道为什么5.0.8安装失败)

npm install -g @vue/cli

创建web项目

vue create web

选择第三个(手动配置) 

选择router,vuex(按空格选择)

选择3.x

是否保存(yes)

保存到哪(package.json)

是否保存模板(y)

保存名字为(train)

进入前段文件

cd web

启动前端

npm run serve

其中package.json相当于maven的pom文件

node module相当于jar包

修改端口号

进入package.json

scripts中的serve后增加--port 9000

快速启动前端工程

右键package.json,选择show npm scripts

集成ant-design vue

安装ant-design vue依赖

npm i ant-design-vue@3.2.15

全局引入依赖 main.js中,新版css文件好像改名了

import Antd from 'ant-design-vue'
createApp(App).use(Antd).use(store).use(router).mount('#app')
import 'ant-design-vue/dist/antd.css'

安装图标

npm install --save@ant-design/icons-vue

全局引入图标依赖,修改app,完整代码如下

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'ant-design-vue/dist/reset.css'
import * as Icons from '@ant-design/icons-vue'
const  app=createApp(App);
app.use(Antd).use(store).use(router).mount('#app');

const icons=Icons;
for (const i in icons){
    app.component(i,icons[i]);
}

增加页面,router下增加

  {
    path: '/login',
    component: () => import( '../views/login.vue')
  }

 新增login.vue文件

<template>
  <a-row class="login">
    <a-col :span="8" :offset="8" class="login-main">
      <h1 style="text-align: center"><rocket-two-tone />&nbsp;12306售票系统</h1>
      <a-form
          :model="loginForm"
          name="basic"
          autocomplete="off"
          @finish="onFinish"
          @finishFailed="onFinishFailed"
      >
        <a-form-item
            label=""
            name="mobile"
            :rules="[{ required: true, message: '请输入手机号!' }]"
        >
          <a-input v-model:value="loginForm.mobile" placeholder="手机号"/>
        </a-form-item>

        <a-form-item
            label=""
            name="code"
            :rules="[{ required: true, message: '请输入验证码!' }]"
        >
          <a-input v-model:value="loginForm.code">
            <template #addonAfter>
              <a @click="sendCode">获取验证码</a>
            </template>
          </a-input>
          <!--<a-input v-model:value="loginForm.code" placeholder="验证码"/>-->
        </a-form-item>

        <a-form-item>
          <a-button type="primary" block html-type="submit">登录</a-button>
        </a-form-item>

      </a-form>
    </a-col>
  </a-row>
</template>

<script>
import { defineComponent, reactive } from 'vue';
export default defineComponent({
  name: "login-view",
  setup() {
    const loginForm = reactive({
      mobile: '13000000000',
      code: '',
    });
    const onFinish = values => {
      console.log('Success:', values);
    };
    const onFinishFailed = errorInfo => {
      console.log('Failed:', errorInfo);
    };
    return {
      loginForm,
      onFinish,
      onFinishFailed,
    };
  },
});
</script>

<style>
.login-main h1 {
  font-size: 25px;
  font-weight: bold;
}
.login-main {
  margin-top: 100px;
  padding: 30px 30px 20px;
  border: 2px solid grey;
  border-radius: 10px;
  background-color: #fcfcfc;
}
</style>

新增发送验证码接受类,参数大体和register一致,增加了正则表达式

public class MemberSendCodeReq {
    @NotBlank(message = "【手机号】不能为空")
    @Pattern(regexp = "^1\\d{10}$",message = "手机号格式错误")
    private String mobile;

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    @Override
    public String toString() {
        return "MemberRegisterReq{" +
                "mobile='" + mobile + '\'' +
                '}';
    }
}

封装获得手机号用户代码

    private Member selectByMobile(String mobile) {
        MemberExample memberExample=new MemberExample();
        memberExample.createCriteria().andMobileEqualTo(mobile);
        List<Member> list=memberMapper.selectByExample(memberExample);
        return list.get(0);
    }

新增sendCode接口和实现

如果存在,则插入,并打印日志

生成验证码

    @PostMapping("/sendCode")
    public CommonResp sendCode(@Valid@RequestBody MemberSendCodeReq req){
        memberService.sendCode(req);
        return new CommonResp();
    }
    public void sendCode(MemberSendCodeReq req) {
        Member member=selectByMobile(req.getMobile());
        if(ObjectUtil.isNull(member)){
            member.setMobile(req.getMobile());
            member.setId(SnowUtil.getSnowflaskNextId());
            memberMapper.insert(member);
            LOG.info("手机号{}不存在,执行注册",req.getMobile());
        }
        else{
            LOG.info("手机号{}不存在,执行登录");
        }
        String code= RandomUtil.randomString(4);

    }

新增登录接口

    @PostMapping("/login")
    public CommonResp<MemberLoginResp> login(@Valid@RequestBody MemberLoginReq req){
        return memberService.login(req);
    }

业务层

    public CommonResp<MemberLoginResp> login(MemberLoginReq req) {
        Member member=selectByMobile(req.getMobile());
        if(ObjectUtil.isNull(member)){
            throw new BusinessException(BusinessExceptionEnum.MEMBER_MOBILE_EXIST);
        }
        if(!req.getCode().equals("8888")){
            throw new BusinessException(BusinessExceptionEnum.CODE_ERROR);
        }
        return new CommonResp<>(BeanUtil.copyProperties(member,MemberLoginResp.class));
    }

添加异常类

    MEMBER_MOBILE_EXIST("手机号已注册"),
    MEMBER_MOBILE_NOT_EXIST("请先获取验证码"),
    CODE_ERROR("短信验证码错误");

添加注册接口返回类

public class MemberLoginResp {
    private Long id;

    private String mobile;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

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

    @NotBlank(message = "【短信验证码】不能为空")
    private String code;


    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    @Override
    public String toString() {
        return "MemberRegisterReq{" +
                "mobile='" + mobile + '\'' +
                '}';
    }
}

完善前端登录功能

安装axios

 npm install axios

导入依赖

login.vue script中增加

import axios from "axios";
    const sendCode = () => {
      axios.post("http://localhost:8000/member/member/sendCode", {
        mobile: loginForm.mobile
      }).then(response => {
        console.log(response);
      });
    };
    return {
      loginForm,
      onFinish,
      onFinishFailed,
      sendCode
    };

解决跨域问题

gateway中配置文件中增加

# 允许请求来源(老版本叫allowedOrigin)
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedOriginPatterns=*
# 允许携带的头信息
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedHeaders=*
# 允许的请求方式
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedMethods=*
# 是否允许携带cookie
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowCredentials=true
# 跨域检测的有效期,会发起一个OPTION请求
spring.cloud.gateway.globalcors.cors-configurations.[/**].maxAge=3600

完善前端工程

<template>
  <a-row class="login">
    <a-col :span="8" :offset="8" class="login-main">
      <h1 style="text-align: center"><rocket-two-tone />&nbsp;12306售票系统</h1>
      <a-form
          :model="loginForm"
          name="basic"
          autocomplete="off"
          @finish="onFinish"
          @finishFailed="onFinishFailed"
      >
        <a-form-item
            label=""
            name="mobile"
            :rules="[{ required: true, message: '请输入手机号!' }]"
        >
          <a-input v-model:value="loginForm.mobile" placeholder="手机号"/>
        </a-form-item>

        <a-form-item
            label=""
            name="code"
            :rules="[{ required: true, message: '请输入验证码!' }]"
        >
          <a-input v-model:value="loginForm.code">
            <template #addonAfter>
              <a @click="sendCode">获取验证码</a>
            </template>
          </a-input>
          <!--<a-input v-model:value="loginForm.code" placeholder="验证码"/>-->
        </a-form-item>

        <a-form-item>
          <a-button type="primary" block @click="login">登录</a-button>
        </a-form-item>


      </a-form>
    </a-col>
  </a-row>
</template>

<script>
import { defineComponent, reactive } from 'vue';
import axios from "axios";
import { notification } from 'ant-design-vue';

export default defineComponent({
  name: "login-view",
  setup() {
    const loginForm = reactive({
      mobile: '13000000000',
      code: '',
    });
    const onFinish = values => {
      console.log('Success:', values);
    };
    const onFinishFailed = errorInfo => {
      console.log('Failed:', errorInfo);
    };
    const sendCode = () => {
      axios.post("http://localhost:8000/member/member/sendCode", {
        mobile: loginForm.mobile
      }).then(response => {
        console.log(response);
        let data = response.data;
        if (data.success) {
          notification.success({ description: '发送验证码成功!' });
          loginForm.code = "8888";
        } else {
          notification.error({ description: data.message });
        }
      });
    };

    const login = () => {
      axios.post("http://localhost:8000/member/member/login", loginForm).then(response => {
        let data = response.data;
        if (data.success) {
          notification.success({ description: '登录成功!' });
          console.log("登录成功:", data.content);
        } else {
          notification.error({ description: data.message });
        }
      })
    };
    return {
      loginForm,
      sendCode,
      login
    };
  },
});
</script>

<style>
.login-main h1 {
  font-size: 25px;
  font-weight: bold;
}
.login-main {
  margin-top: 100px;
  padding: 30px 30px 20px;
  border: 2px solid grey;
  border-radius: 10px;
  background-color: #fcfcfc;
}
</style>

为前端增加拦截器,打印前后端交互信息

main.js下新增

import axios from 'axios';
axios.interceptors.request.use(function (config) {
    console.log('请求参数:', config);
    return config;
}, error => {
    return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
    console.log('返回结果:', response);
    return response;
}, error => {
    console.log('返回错误:', error);
    return Promise.reject(error);
});

login.vue删除console.log相关日志

main.js下新增

axios.defaults.baseURL = process.env.VUE_APP_SERVER;
console.log('环境:', process.env.NODE_ENV);
console.log('服务端:', process.env.VUE_APP_SERVER);

新增文件.env.dev,配置文件需要以VUE_APP开头

NODE_ENV=development
VUE_APP_SERVER=http://localhost:8000

npm控制台中选择dev启动

新增及完善主页面

main.vue

<template>
  <a-row class="login">
    <a-col :span="8" :offset="8" class="login-main">
      <h1 style="text-align: center"><rocket-two-tone />&nbsp;12306售票系统</h1>
      <a-form
          :model="loginForm"
          name="basic"
          autocomplete="off"
          @finish="onFinish"
          @finishFailed="onFinishFailed"
      >
        <a-form-item
            label=""
            name="mobile"
            :rules="[{ required: true, message: '请输入手机号!' }]"
        >
          <a-input v-model:value="loginForm.mobile" placeholder="手机号"/>
        </a-form-item>

        <a-form-item
            label=""
            name="code"
            :rules="[{ required: true, message: '请输入验证码!' }]"
        >
          <a-input v-model:value="loginForm.code">
            <template #addonAfter>
              <a @click="sendCode">获取验证码</a>
            </template>
          </a-input>
          <!--<a-input v-model:value="loginForm.code" placeholder="验证码"/>-->
        </a-form-item>

        <a-form-item>
          <a-button type="primary" block @click="login">登录</a-button>
        </a-form-item>


      </a-form>
    </a-col>
  </a-row>
</template>

<script>
import { defineComponent, reactive } from 'vue';
import axios from "axios";
import { notification } from 'ant-design-vue';
import router from "@/router";

export default defineComponent({
  name: "login-view",
  setup() {
    const loginForm = reactive({
      mobile: '13000000000',
      code: '',
    });
    const onFinish = values => {
    };
    const onFinishFailed = errorInfo => {
    };
    const sendCode = () => {
      axios.post("/member/member/sendCode", {
        mobile: loginForm.mobile
      }).then(response => {
        console.log(response);
        let data = response.data;
        if (data.success) {
          notification.success({ description: '发送验证码成功!' });
          loginForm.code = "8888";
        } else {
          notification.error({ description: data.message });
        }
      });
    };

    const login = () => {
      axios.post("/member/member/login", loginForm).then(response => {
        let data = response.data;
        if (data.success) {
          notification.success({ description: '登录成功!' });
        } else {
          notification.error({ description: data.message });
          router.push("/")
        }
      })
    };
    return {
      loginForm,
      sendCode,
      login
    };
  },
});
</script>

<style>
.login-main h1 {
  font-size: 25px;
  font-weight: bold;
}
.login-main {
  margin-top: 100px;
  padding: 30px 30px 20px;
  border: 2px solid grey;
  border-radius: 10px;
  background-color: #fcfcfc;
}
</style>

 the-header.vue

<template>
  <a-layout-header class="header">
    <div class="logo" />
    <a-menu
        v-model:selectedKeys="selectedKeys1"
        theme="dark"
        mode="horizontal"
        :style="{ lineHeight: '64px' }"
    >
      <a-menu-item key="1">nav 11</a-menu-item>
      <a-menu-item key="2">nav 2</a-menu-item>
      <a-menu-item key="3">nav 3</a-menu-item>
    </a-menu>
  </a-layout-header>
</template>

<script>
import {defineComponent, ref} from 'vue';

export default defineComponent({
  name: "the-header-view",
  setup() {

    return {
      selectedKeys1: ref(['2']),
    };
  },
});
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

the-sider.vue

<template>
  <a-layout id="components-layout-demo-top-side-2">
    <the-header-view></the-header-view>
    <a-layout>
      <a-layout-sider width="200" style="background: #fff">
        <a-menu
            v-model:selectedKeys="selectedKeys2"
            v-model:openKeys="openKeys"
            mode="inline"
            :style="{ height: '100%', borderRight: 0 }"
        >
          <a-sub-menu key="sub1">
            <template #title>
              <span>
                <user-outlined />
                subnav 1
              </span>
            </template>
            <a-menu-item key="1">option1</a-menu-item>
            <a-menu-item key="2">option2</a-menu-item>
            <a-menu-item key="3">option3</a-menu-item>
            <a-menu-item key="4">option4</a-menu-item>
          </a-sub-menu>
          <a-sub-menu key="sub2">
            <template #title>
              <span>
                <laptop-outlined />
                subnav 2
              </span>
            </template>
            <a-menu-item key="5">option5</a-menu-item>
            <a-menu-item key="6">option6</a-menu-item>
            <a-menu-item key="7">option7</a-menu-item>
            <a-menu-item key="8">option8</a-menu-item>
          </a-sub-menu>
          <a-sub-menu key="sub3">
            <template #title>
              <span>
                <notification-outlined />
                subnav 3
              </span>
            </template>
            <a-menu-item key="9">option9</a-menu-item>
            <a-menu-item key="10">option10</a-menu-item>
            <a-menu-item key="11">option11</a-menu-item>
            <a-menu-item key="12">option12</a-menu-item>
          </a-sub-menu>
        </a-menu>
      </a-layout-sider>
      <a-layout style="padding: 0 24px 24px">
        <a-breadcrumb style="margin: 16px 0">
          <a-breadcrumb-item>Home</a-breadcrumb-item>
          <a-breadcrumb-item>List</a-breadcrumb-item>
          <a-breadcrumb-item>App</a-breadcrumb-item>
        </a-breadcrumb>
        <a-layout-content
            :style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
        >
          Content
        </a-layout-content>
      </a-layout>
    </a-layout>
  </a-layout>
</template>
<script>
import { UserOutlined, LaptopOutlined, NotificationOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import TheHeaderView from "@/components/the-header";
export default defineComponent({
  name: "main-view",
  components: {
    TheHeaderView,
    UserOutlined,
    LaptopOutlined,
    NotificationOutlined,
  },
  setup() {
    return {
      selectedKeys2: ref(['1']),
      collapsed: ref(false),
      openKeys: ref(['sub1']),
    };
  },
});
</script>
<style>
#components-layout-demo-top-side-2 .logo {
  float: left;
  width: 120px;
  height: 31px;
  margin: 16px 24px 16px 0;
  background: rgba(255, 255, 255, 0.3);
}

.ant-row-rtl #components-layout-demo-top-side-2 .logo {
  float: right;
  margin: 16px 0 16px 24px;
}

.site-layout-background {
  background: #fff;
}
</style>

index.js新增

{
    path: '/',
    component: () => import('../views/main.vue')
  }

login.vue修改

const login = () => {
      axios.post("/member/member/login", loginForm).then(response => {
        let data = response.data;
        if (data.success) {
          notification.success({ description: '登录成功!' });
        } else {
          notification.error({ description: data.message });
          router.push("/")
        }
      })
    };

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值