一般我们的项目分为以下几个部分:
依照官网Element - The world's most popular Vue UI framework 的代码,我简单的做了一个项目的大概内容。
我将头部,左侧菜单栏,主体部分以及尾部都放到了我所创建的common文件夹中。
具体如下:
头部内容:
- <template>
- <div class="header">
- <el-header>
- <div>小说后台管理系统div>
- <div>欢迎:{{ loginUser }} <el-button type="primary">退出el-button>div>
- el-header>
- div>
- template>
- <script>
- export default {
- data(){
- return {
- loginUser:"張三"
- }
- }
- };
- script>
- <style>
- .header{
- width:100%;
- height: 100%;
- }
- .el-header{
- line-height: 60px;
- display: flex;
- justify-content: space-between;
- }
- style>
左侧菜单栏:
- <template>
- <div style="width:200px">
- <el-menu default-active="2" class="el-menu-vertical-demo">
- <el-submenu index="1">
- <template slot="title">
- <i class="el-icon-location">i>
- <span>系统管理span>
- template>
- <el-menu-item-group>
- <el-menu-item index="1-1">系统菜单el-menu-item>
- <el-menu-item index="1-2">参数管理el-menu-item>
- <el-menu-item index="1-3">字典管理el-menu-item>
- el-menu-item-group>
- el-submenu>
- <el-submenu index="2">
- <template slot="title">
- <i class="el-icon-location">i>
- <span>小说管理span>
- template>
- <el-menu-item-group>
- <el-menu-item index="2-1">章节数据el-menu-item>
- <el-menu-item index="2-2">小说数据el-menu-item>
- <el-menu-item index="2-3">阅读图标el-menu-item>
- el-menu-item-group>
- el-submenu>
- el-menu>
- div>
- template>
- <script>
- export default {};
- script>
主体:
- <template>
- <el-main>
- <el-table :data="tableData" border style="width: 100%">
- <el-table-column prop="date" label="日期" width="180"> el-table-column>
- <el-table-column prop="name" label="姓名" width="180"> el-table-column>
- <el-table-column prop="address" label="地址"> el-table-column>
- el-table>
-
- <el-pagination
- :current-page="currentPage"
- :page-sizes="[5, 10, 20, 50]"
- :page-size="100"
- layout="total,sizes, prev, pager, next,jumper"
- :total="400"
- >
- el-pagination>
- el-main>
- template>
- <script>
- export default {
- data() {
- return {
- tableData: [
- {
- date: "2016-05-02",
- name: "王小虎",
- address: "上海市普陀区金沙江路 1518 弄",
- },
- {
- date: "2016-05-04",
- name: "王小虎",
- address: "上海市普陀区金沙江路 1517 弄",
- },
- {
- date: "2016-05-01",
- name: "王小虎",
- address: "上海市普陀区金沙江路 1519 弄",
- },
- {
- date: "2016-05-03",
- name: "王小虎",
- address: "上海市普陀区金沙江路 1516 弄",
- },
- ],
- };
- },
- };
- script>
尾部:
- <template>
- <el-card>
- <div class="footer">createby 婷姐div>
- el-card>
- template>
- <style>
- .footer{
- text-align: center;
- }
- style>
那做好的公共部分又是如何导入到整体项目中的呢?
先写一个整体的vue页面,我这边起名为Home.vue。
依照官网复制布局容器的相关代码,将其中的四个部分换成我所写的四个组件vue。
- <template>
- <div>
- <el-container>
- <Header/>
- <el-container class="content">
- <Menu/>
- <el-container>
- <Main/>
- <el-footer>
- <Footer/>
- el-footer>
- el-container>
- el-container>
- el-container>
- div>
- template>
-
- <script>
- import Header from './common/Header.vue';
- import Menu from './common/Menu.vue';
- import Main from './common/Main.vue';
- import Footer from './common/Footer.vue';
- export default {
- components:{
- Header,
- Menu,
- Main,
- Footer
- }
- }
- script>
- <style>
- .content{
- width: 100%;
- position: absolute;
- top: 80px;
- bottom: 0px;
- }
- style>
在APP.vue中将其导入进行展示。
- <template>
- <div id="app">
- <Home/>
- div>
- template>
-
- <script>
- import Home from './components/Home.vue';
- export default{
- name:"App",
- components:{
- Home
- }
-
- }
- script>
效果如下:
打开你放脚手架的vue文件夹,通过该文件夹打开cmd命令窗口,新建项目。
在vscode中打开该项目,首先创建vue.config.js来开启自动启动服务。
- module.exports = {
- devServer :{
- open : true //自动启动设置
- }
- }
在终端窗口为该项目安装element-ui。
npm i element-ui -S
在main.js文件中引入element-ui。
将HelloWord.vue 改名为Login.vue,并更改其内容,做基本的输入用户名和密码以及对其校验,在点击立即登录以及重置时触发的方法。
- <template>
- <div class="login">
- <el-card>
- <h1>后台登录h1>
- <el-form ref="loginForm" :model="user" :rules="rules" label-width="80px">
- <el-form-item label="用户名" prop="name">
- <el-input placeholder="请输入用户名" v-model="user.name">el-input>
- el-form-item>
- <el-form-item label="密码" prop="password">
- <el-input placeholder="请输入密码" v-model="user.password" show-password>el-input>
- el-form-item>
- <el-form-item>
- <el-button type="primary" @click="onSubmit">立即登录el-button>
- <el-button type="primary" @click="onReset">重置el-button>
- el-form-item>
- el-form>
- el-card>
- div>
- template>
- <script>
- export default {
- name: "Login",
- data() {
- return {
- user: {
- name: "",
- password: "",
- },
- rules: {
- name: [{ required: true, message: "请输入用户名", trigger: "blur" }],
- password: [{ required: true, message: "请输入密码", trigger: "blur" }],
- },
- };
- },
-
- methods: {
- onSubmit() {
- this.$refs.loginForm.validate((valid) => {
- if (!valid) {
- this.$message.error("请将信息填写完整");
- } else{
- //提交
- console.log("提交")
- }
- });
- },
- onReset() {
- this.$refs.loginForm.resetFields();
- },
- },
- };
- script>
- <style>
- .login {
- width: 600px;
- height: 600px;
- margin: 0 auto;
- margin-top: 100px;
- text-align: center;
- }
- style>
前台基本的页面写好之后就需要从后台获取数据了,首先先创建数据库并添加数据,自行添加即可。
添加完毕后创建一个springboot的项目,做基本的用户登录校验。
打开pom文件,修改Mysql的版本号。
在配置文件中配置与数据库的连接。
实体类:
- package com.zb.entity;
-
- 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.io.Serializable;
- import java.util.Date;
-
- @AllArgsConstructor
- @NoArgsConstructor
- @Data
- @ToString
- @TableName("customer")
- public class Customer implements Serializable {
- @TableId(value = "id",type = IdType.AUTO)
- private Integer id;
- @TableField("name")
- private String name;
- @TableField("password")
- private String password;
- @TableField("gender")
- private Integer gender;
- @TableField("mobile")
- private String mobile;
- @TableField("birthday")
- private Date birthday;
- @TableField("money")
- private Double money;
- @TableField("isVIP")
- private Integer isVIP;
- }
mapper接口:
- package com.zb.mapper;
-
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.zb.entity.Customer;
- import org.apache.ibatis.annotations.Mapper;
-
- @Mapper
- public interface CustomerMapper extends BaseMapper
{ - }
service接口:
- package com.zb.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.zb.entity.Customer;
-
- public interface CustomerService extends IService
{ - }
service实现类:
- package com.zb.service.impl;
-
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.zb.entity.Customer;
- import com.zb.mapper.CustomerMapper;
- import com.zb.service.CustomerService;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
-
- @Service
- @Transactional
- public class CustomerServiceImpl extends ServiceImpl
,Customer> implements CustomerService { - }
此时我们需要思考一个问题,我们的后台和前端利用ajax技术进行数据交互,此时登录用户该如何存到前端?
这边我们需要了解一些知识点:
localStorage:用来存储信息的一块区域,以键值对方式存储,键值对类型均为String,长期存放。
sessionStorage:关闭浏览器则清除所存内容。
假设我们在vue创建完成时在localStorage存放一个对象。
那么我们在application里面即可看到所存的内容。
而这边登录的话一般使用sessionStorage更合适。登录除了存放用户名之外,还需要存放token。
登录场景:
前端发起登录请求到后台,后台根据用户名和密码查询用户,如果登录成功则创建一个token令牌,并且以token作为key,登录用户作为值存到redis中,防止登录失效,将数据返回给前端,由前端来保存。
其他业务场景:
登录可能存在失效的情况,前端如果在不确定登录是否失效的情况下想要通过登录用户获取数据,则首先要获取token,如果拿不到token,则需要重新登录,如果拿到了token,并且token对应的value有登录对象,则返回所需要的数据给前端,如果redis缓存中不存在该token对应的登录对象,则需要重新登录。
理解完之后继续进行代码操作:
首先开启redis服务:
并打开图形化软件:
在com.zb下创建redis配置文件:
- package com.zb;
-
- import com.fasterxml.jackson.annotation.JsonAutoDetect;
- import com.fasterxml.jackson.annotation.PropertyAccessor;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.cache.annotation.CachingConfigurerSupport;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.Primary;
- import org.springframework.data.redis.cache.RedisCacheConfiguration;
- import org.springframework.data.redis.cache.RedisCacheManager;
- import org.springframework.data.redis.cache.RedisCacheWriter;
- import org.springframework.data.redis.connection.RedisConnectionFactory;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
- import org.springframework.data.redis.serializer.RedisSerializationContext;
- import org.springframework.data.redis.serializer.StringRedisSerializer;
-
- @Configuration
- public class RedisConfiguration extends CachingConfigurerSupport {
-
- @Autowired
- private RedisConnectionFactory redisConnectionFactory;
-
-
- @Bean
- @Primary
- public RedisTemplate
redisTemplate(RedisConnectionFactory redisConnectionFactory) { - Jackson2JsonRedisSerializer
- ObjectMapper objectMapper = new ObjectMapper();
- objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
- serializer.setObjectMapper(objectMapper);
-
- RedisTemplate
redisTemplate = new RedisTemplate<>(); - redisTemplate.setConnectionFactory(redisConnectionFactory);
- redisTemplate.setKeySerializer(new StringRedisSerializer());
- redisTemplate.setValueSerializer(serializer);
- redisTemplate.setHashKeySerializer(new StringRedisSerializer());
- redisTemplate.setHashValueSerializer(serializer);
- redisTemplate.afterPropertiesSet();
-
- return redisTemplate;
- }
-
- @Bean
- public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
- RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
- RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
- .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
- return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
- }
- }
注意:这边的redisconnectionfactory对象版本太高可能用不了,注意修改版本号:
在启动类上添加开启全局缓存注解:
创建一个token的工具类:
- package com.zb.util;
-
- import java.util.UUID;
-
- public class TokenUtil {
- public static String createToken(){
- String token = UUID.randomUUID().toString().replaceAll("-","");
- return token;
- }
- }
controller控制器:
- package com.zb.controller;
-
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import com.zb.entity.Customer;
- import com.zb.service.CustomerService;
- import com.zb.util.TokenUtil;
- import org.omg.PortableInterceptor.SUCCESSFUL;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.web.bind.annotation.CrossOrigin;
- 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 javax.xml.transform.Templates;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.UUID;
- import java.util.concurrent.TimeUnit;
-
- @RestController
- @RequestMapping("/customer")
- //跨域
- @CrossOrigin("*")
- public class CustomerController {
- @Resource
- private CustomerService service;
- @Resource
- private RedisTemplate<String,Object> redisTemplate;
-
- @RequestMapping("/login")
- public Map<String,Object> login(@RequestBody(required = false)Customer customer){
- //做一个简单的map对象用来将数据返回给前端
- Map<String,Object> map = new HashMap<>();
-
- QueryWrapper<Customer> wrapper = new QueryWrapper<>();
- wrapper.eq("name",customer.getName());
- wrapper.eq("password",customer.getPassword());
- Customer loginCustomer = service.getOne(wrapper);
- if(loginCustomer!=null){
- //登录成功
- String token = TokenUtil.createToken();
- //存redis
- redisTemplate.opsForValue().set(token,loginCustomer,6,TimeUnit.HOURS);
- map.put("token",token);
- map.put("name",customer.getName());
- map.put("flag","success");
-
- }else{
- //登录失败
- map.put("flag","error");
- map.put("message","用户名或密码不正确");
- }
- return map;
- }
-
- }
此时在redis缓存中即可看到缓存的内容:
这时后端已经把数据吐出来了,那么前端就要写登录相关的代码了,首先需要下载axios来发送请求。
在终端窗口通过命令进行下载:
npm i -S axios
在main.js中引入axios并挂载原型:
最后更新Login.vue的代码:
- <template>
- <div class="login">
- <el-card>
- <h1>后台登录h1>
- <el-form ref="loginForm" :model="user" :rules="rules" label-width="80px">
- <el-form-item label="用户名" prop="name">
- <el-input placeholder="请输入用户名" v-model="user.name">el-input>
- el-form-item>
- <el-form-item label="密码" prop="password">
- <el-input placeholder="请输入密码" v-model="user.password" show-password>el-input>
- el-form-item>
- <el-form-item>
- <el-button type="primary" @click="onSubmit">立即登录el-button>
- <el-button type="primary" @click="onReset">重置el-button>
- el-form-item>
- el-form>
- el-card>
- div>
- template>
- <script>
- export default {
- name: "Login",
- data() {
- return {
- user: {
- name: "",
- password: "",
- },
- rules: {
- name: [{ required: true, message: "请输入用户名", trigger: "blur" }],
- password: [{ required: true, message: "请输入密码", trigger: "blur" }],
- },
- };
- },
-
- methods: {
- onSubmit() {
- this.$refs.loginForm.validate((valid) => {
- if (!valid) {
- this.$message.error("请将信息填写完整");
- } else{
- //提交
- this.axios.post("http://localhost:8088/customer/login",this.user).then((response)=>{
- if(response.status == 200 && response.data.flag == "success"){
- sessionStorage.setItem("token",response.data.token);
- sessionStorage.setItem("user",response.data.name);
- //路由跳转 TODO
- this.$message.success("登录成功");
- }else{
- this.$message.error(response.data.message);
- }
- }).catch((error)=>{
- console.log(error);
- })
-
- }
- });
- },
- onReset() {
- this.$refs.loginForm.resetFields();
- },
- },
- created(){
- //用来存储信息的一块区域,以键值对方式存储,键值对类型均为String
- //localStorage长期拥有
- //sessionStorage关闭浏览器则清除
- //除了存放用户名之外,同时存储token
- //localstorage.setItem("username","军军");
- //let name = localStorage.getItem("user");
- //console.log(name);
- // sessionStorage.setItem("user","张三");
- // let name =sessionStorage.getItem("user");
- // console.log(name);
- }
- };
- script>
- <style>
- .login {
- width: 600px;
- height: 600px;
- margin: 0 auto;
- margin-top: 100px;
- text-align: center;
- }
- style>
最后的效果如图所示: