基于Springboot+mybatis+redis+Vue一个员工信息系统

前言

这可以说是我的第二篇博客了,这篇博客是在学习完SpringBoot课程之后,开始动手做的第一个项目,采用的是前后端分离的形式。但是前端页面并不是自己写的。做的工作只有后端接口的开发。这样对于第一次接触前后端分离项目的同学来说,是一件比较好的事情。通过这个小项目,我们进一步的了解到前后端分离的概念。体验到作为后端人员我们需要做哪些工作。

好了,接下来就进入正题了。

技术栈

  • SpringBoot
  • Mybatis
  • 连接池:Durid
  • 缓存:Redis
  • 前端:Vue
  • axios

需求分析

本次项目共分为用户模块和员工模块

用户模块:
	1.用户登录
	2.用户注册
	3.验证码实现
	4.用户展现
员工模块:
	1.员工列表展现
	2.员工列表添加
	3.员工删除
	4.员工列表加入redis缓存

数据库设计

1、数据表设计

用户表:

idusernamerealnamepasswordsexstautsregisterTime

员工表

idnamepath(头像)salaryage

2、创建库表

		# 数据库 emp
		user emp
		
		create table t_user(
            id int(6) primary key auto_increment,
            username varchar(60),
            realname varchar(60),
            password varchar(50),
            sex      varchar(4),
            status   varchar(4),
            regsterTime timestamp
        );

		create table t_emp(
            id int(6) primary key auto_increment,
            name varchar(40),
            path varchar(100),
            salary double(10,2),
            age  int(3)
        );

环境搭建

1、创建项目结构

项目名:ems_vue
包结构:
	src/main/java
				com.xxxx
						controller
						mapper
						pojo
						service
						utils
	src/main/resource
    				com.xxxx
    						mapper   用来存放mybatis的mapper配置文件
    				statis  用来存放静态资源
    				application.properties    springboot 的配置文件 

编码环节

1、配置文件的编写

# 配置项目访问的路径名
server.servlet.context-path=/ems_vue

# 数据库的配置
# 端口号
server.port=8080
# 采用的连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/emp?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

# 配置Mybatis的mapper的路径
mybatis.mapper-locations=classpath:com/feng/mapper/*.xml

# 起别名
mybatis.type-aliases-package=com.feng.pojo

# 打印日志的等级
logging.level.com,feng.dao=debug
logging.level.com,feng.service=info
logging.level.com,feng.controller=info


2、测试

此过程看看项目是否能够正常的运行

编写一个TextController

package com.feng.controller;


import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TextController {

    @RequestMapping("/hello")
    public String hello()
    {
        return "hello";
    }
}

当项目运行成功时,我们就可以进行我下一步的操作了。

3、引入静态资源

即Vue.js,axios,js机器其他的一些静态页面

4、pojo的实现

user类:

@Data
//链式编程
@Accessors(chain = true)
public class User {

    private String id;  //string类型的api相对较多
    private String username;
    private String realname;
    private String password;
    private String sex;
    private String status;
    private Date regsterTime;
}

业务实现

1、验证码的实现

在用户进行注册是需要进行验证码的验证。

首先我们需要在注册的页面进行验证码渲染。

<tr>
   <td valign="middle" align="right">
      验证码:
   </td>
   <td valign="middle" align="left">
      <input type="text" v-model="code" class="inputgri" name="number" />
   </td>
   <td>
      <img id="num" :src="url" />
      <a href="javascript:;" @click="getImg">换一张</a>
   </td>
</tr>
<!--引入Vue相关的JS-->
<script src="/ems_vue/js/vue.js"></script>
<script src="/ems_vue/js/axios.min.js"></script>
<script>
	var app = new Vue({
		el: "#wrap",
		data: {
			url: "",
			user: {
				sex: "男"
			},
			code: "",
		},

		methods: {
			//更换验证码
			getImg(){
				this.getSrc();
			},

			//封装获取验证码的函数
			getSrc(){
				var _this = this;
				//?time="+Math.random()  拼接一个随机的时间戳,用来防止浏览器的缓存
				axios.get("http://localhost:8080/ems_vue/user/getImage?time="+Math.random()).then(res=>{
					console.log(res.data);
					_this.url = res.data;

				});
			},

			//用来注册用户信息
			register(){
				axios.post("http://localhost:8080/ems_vue/user/register?code="+this.code,this.user).then(res=>{
					console.log(res.data);
					if(res.data.state){
						alert(res.data.msg+",点击跳转志登录页面");
						location.href="/ems_vue/login.html";
					}else{
						alert(res.data.msg);
					}
				});
			}
		},

		//由于验证码是在页面加载时生成,因此需要Vue得生命周期函数
		created(){
			this.getSrc();
		}
	})
</script>

更换验证码的操作,需要通过@click="getImg"给该链接绑定一个单击事件,就会执行methods中的getImg方法。

//封装获取验证码的函数
			getSrc(){
				var _this = this;
				//?time="+Math.random()  拼接一个随机的时间戳,用来防止浏览器的缓存
				axios.get("http://localhost:8080/ems_vue/user/getImage?time="+Math.random()).then(res=>{
					console.log(res.data);
					_this.url = res.data;

				});
			},

这部分就是验证码的具体请求:

由于在ES6语法中,this的指向改变了,因此我们需要保留this的指向。通过axios的get请求像后端发送请求,后端接口返回的base64类型字符串赋值给data中的url。然后image器进行解析。

后端接口的实现:


@RequestMapping("getImage")
public String getImageCode(HttpServletRequest request) throws IOException {
    //1、使用工具类生成验证码
    //参数代表着生成验证码的长度。
    String code = VerifyCodeUtils.generateVerifyCode(4);

    //2、放入servletContext作用域  (前后端分离的项目是没有session的概念的)
    request.getServletContext().setAttribute("code",code);

    //3、将图片转化为Base64类型输出
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    VerifyCodeUtils.outputImage(220,60,byteArrayOutputStream,code);

    //如果image要解析base64,需要拼上一个处理 (拼接需要注意,不能少一个字符)
    String s ="data:image/png;base64," + Base64Utils.encodeToString(byteArrayOutputStream.toByteArray());

    return s;

2、用户的注册

<h1>
   注册
</h1>
<form action="login.html" method="post">
   <table cellpadding="0" cellspacing="0" border="0"
      class="form_table">

      <tr>
         <td valign="middle" align="right">
            用户名:
         </td>
         <td valign="middle" align="left">
            <input type="text" class="inputgri" v-model="user.username" name="username" />
         </td>
      </tr>

      <tr>
         <td valign="middle" align="right">
            真实姓名:
         </td>
         <td valign="middle" align="left">
            <input type="text" class="inputgri" v-model="user.realname" name="name" />
         </td>
      </tr>

      <tr>
         <td valign="middle" align="right">
            密码:
         </td>
         <td valign="middle" align="left">
            <input type="password" class="inputgri" v-model="user.password" name="pwd" />
         </td>
      </tr>

      <tr>
         <td valign="middle" align="right">
            性别:
         </td>
         <td valign="middle" align="left"><input type="radio" class="inputgri" v-model="user.sex" name="sex" value="" checked="checked"/><input type="radio" class="inputgri" v-model="user.sex" name="sex" value=""/>
         </td>
      </tr>
      
      <tr>
         <td valign="middle" align="right">
            验证码:
         </td>
         <td valign="middle" align="left">
            <input type="text" v-model="code" class="inputgri" name="number" />
         </td>
         <td>
            <img id="num" :src="url" />
            <a href="javascript:;" @click="getImg">换一张</a>
         </td>
      </tr>

   </table>
    <p>
        <input type="button" @click="register" class="button" value="Submit &raquo;" />
    </p>

我们首先通过v-model进行数据的双向绑定。将提交按钮添加一个单机事件,当提交时就会执行methods中的register。执行方法中的axios请求。向后台发送请求,并且把输入的code数据返回给后端,进行判断验证码的正确。后端交给前端一个state状态,来进行判断时候注册成功。如果成功,就会跳转至登录页面,否则就会打印出来相关的错误信息。

//用来注册用户信息
register(){
   axios.post("http://localhost:8080/ems_vue/user/register?code="+this.code,this.user).then(res=>{
      console.log(res.data);
      if(res.data.state){
         alert(res.data.msg+",点击跳转志登录页面");
         location.href="/ems_vue/login.html";
      }else{
         alert(res.data.msg);
      }
   });

后端注册接口的实现

mapper层:

@Mapper //用来创建dao对象
@Repository
public interface UserMapper {

    	//增加用户
       int save(User user);
       User findByUserName(String username);
}

<!--useGeneratedKeys: 把新增加的主键赋值到自己定义的keyProperty(id)中 -->
<insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">
    insert into emp.t_user values (#{id},#{username},#{realname},#{password},#{sex},#{status},#{regsterTime})
</insert>

<select id="findByUserName" parameterType="String" resultType="User">
    select id,username,realname,password,sex,status,regsterTime
    from emp.t_user where username = #{username}
</select>

service层:

public interface UserService {

    //注册用户
    void save(User user);

    //根据名字查询用户
    User findByUserName(String username);

    //登录查询
    User login(User user);
}
@Autowired
private UserMapper userMapper;

 //根据用户名查询用户
    @Override
    public User findByUserName(String username) {
        return userMapper.findByUserName(username);
    }


@Override
public void save(User user) {

    //第一步:要根据用户输入的用户名判断用户是否存在
    //AlreadyUser:  已经存在得用户,如果用户已经存在则,注册失败。
    User AlreadyUser = findByUserName(user.getUsername());
    if(AlreadyUser == null)
    {
        //注册成功
        user.setStatus("已激活");
        user.setRegsterTime(new Date());

        userMapper.save(user);
    }
    else
    {
        //注册失败抛出异常
        throw new RuntimeException("用户名已经存在");  
    }

}

Controller层:

//处理用户注册
@RequestMapping("register")
//@RequestBody:后端接收前端传来的json字符串中的数据,同时,前端只能以post方式提交
public Map<String,Object> register(@RequestBody User user,String code,HttpServletRequest request)
{

    //打印日志
    log.info("用户信息:[{}]",user.toString());
    log.info("用户输入的验证码信息:[{}]",code);
    
    //用来保存返回给前端的一些数据
    Map<String,Object> map = new HashMap<>();

    try {
        //拿到验证码
        String  key = (String) request.getServletContext().getAttribute("code");
        System.out.println("验证码为"+key);

        //equalsIgnoreCase  :不区分大小写
        if(key.equalsIgnoreCase(code))
        {
            map.put("state",true);
            map.put("msg","提示:注册成功");
            userService.save(user);
        }
        else
        {
            System.out.println("验证码错误");
            throw new RuntimeException("验证码出现错误");
        }
    }catch (Exception e){
        e.printStackTrace();
        map.put("state",false);
        map.put("msg","提示:"+e.getMessage());
    }
    return map;
}

3、用户登录

前端操作:

<h1>
    login
</h1>
<form action="emplist.html" method="post">
    <table cellpadding="0" cellspacing="0" border="0"
           class="form_table">

        <tr>
            <td valign="middle" align="right">
                username:
            </td>
            <td valign="middle" align="left">
                <input type="text" class="inputgri" v-model="user.username" name="name" />
            </td>
        </tr>

        <tr>
            <td valign="middle" align="right">
                password:
            </td>
            <td valign="middle" align="left">
                <input type="password" class="inputgri" v-model="user.password" name="pwd" />
            </td>
        </tr>

    </table>
    <p>
        <input type="button" @click="login" class="button" value="Submit &raquo;" />
        &nbsp;&nbsp;
        <a href="/ems_vue/regist.html">注册</a>
    </p>
</form>

<!--省略了一些其他的标签-->
.........

<!--引入Vue相关的JS-->
<script src="/ems_vue/js/vue.js"></script>
<script src="/ems_vue/js/axios.min.js"></script>
<script>
	var app = new Vue({
		el: "#wrap",
		data: {
			user:{}, //用来保存登陆的用户数据
		},
		methods: {
			//用户登录的方法
			login(){
				console.log(this.user);
				//发送登录请求
				axios.post("http://localhost:8080/ems_vue/user/login",this.user).then(res=>{
					console.log(res.data);
					if(res.data.state){
						alert(res.data.msg+",点击确定进入主页");
						//将登录信息放到localStorage
						localStorage.setItem("user",JSON.stringify(res.data.loginUser))
						location.href="/ems_vue/emplist.html";
					}else{
						alert(res.data.msg);
					}
				})
			}
		}
	});
</script>
  1. 通过 v-model把表单中用户的信息和vue中data中的user进行了双向绑定
  2. 当点击提交按钮时,通过@click=‘login’ 绑定了一个单机事件,此时就会这些那个methods中的login方法。此时就会通过axios向后台提交表单数据,后端通过判断user是否存在,传递给前端一个state状态,如果为true,则会跳转到员工信息转世界面。并将员工信息保存在localStorage,以防止用户的非法登录(相当于是一个拦截器的作用)。

后端接口实现:

mapper层省略,上文有

service层:


//根据用户名查询用户
@Override
public User findByUserName(String username) {
    return userMapper.findByUserName(username);
}

//登录查询
@Override
public User login(User user) {

    //1、根据用户名差
    User loginUser = userMapper.findByUserName(user.getUsername());
    if(loginUser != null)
    {
        //2、比较密码
        if(loginUser.getPassword().equals(user.getPassword()))
        {
            return loginUser;
        } else {
            throw new RuntimeException("密码错误");
        }
    }
    else{
        throw new RuntimeException("用户名错误");
    }
}
  1. 登录查询中调用一个 findByUserName方法,根据表单提交的username进行判断,
  2. 如果loginUser为空则登录失败,否则成功。

controller层:

@PostMapping("login")
public Map<String ,Object> login(@RequestBody User user)
{

    log.info("当前登录用户的信息[{}]",user.toString());
    Map<String, Object> map = new HashMap<>();
    try {
        User loginUser = userService.login(user);
        map.put("state",true);
        map.put("msg","登录成功");
        map.put("loginUser",loginUser);
    } catch (Exception e) {
        e.printStackTrace();
        map.put("state",false);
        map.put("msg",e.getMessage());
    }

    return map;
}

这里应该没有什么好解释的,大家理解了整个流程思路也就差不多可以写出来了。

接下来就是员工的一些操作了。

员工业务操作

pojo

@Data
//链式编程
@Accessors(chain = true)
public class Emp {

    private String id;
    private String name;
    private String path;
    private Double salary;
    private Integer age;

}

员工列表展现

前端核心代码:

<table class="table">
   <tr class="table_header">
      <td>
         ID
      </td>
      <td>
         Name
      </td>
      <td>
         Photo
      </td>
      <td>
         Salary
      </td>
      <td>
         Age
      </td>
      <td>
         Operation
      </td>
   </tr>
   <tr v-for="(emp,index) in emps" :key="emp.id" :class="index%2==0?'row1':'row2'">
      <td>
         {{emp.id}}
      </td>
      <td>
         {{emp.name}}
      </td>
      <td>
         <img :src="'/ems_vue/'+emp.path" style="height: 60px;">
      </td>
      <td>
         {{emp.salary}}
      </td>
      <td>
         {{emp.age}}
      </td>
      <td>
         <a href="javascript:;" @click="delEmp(emp.id)">delete emp</a>&nbsp;<a :href="'/ems_vue/updateEmp.html?id='+emp.id">update emp</a>
      </td>
   </tr>
</table>
<p>
   <input type="button" class="button" value="Add Employee" onclick="location='addEmp.html'"/>
</p>

<p>
    <input type="button" class="button" value="Add Employee" onclick="location='addEmp.html'"/>
</p>

<!--引入Vue相关的JS-->
<script src="/ems_vue/js/vue.js"></script>
<script src="/ems_vue/js/axios.min.js"></script>
<script>
	var app = new Vue({
		el: "#wrap",
		data: {
			user: {	//用来保存用户登录的信息

			},
			emps: [],
			time: ""
		},
		methods: {

			//安全退出
			logout(){
				localStorage.removeItem("user");
				location.reload(true);  //刷新页面
			},

			//删除员工
			delEmp(id){
				if(window,confirm("确定要删除这条员工信息吗")){
					var _this = this;
					axios.get("http://localhost:8080/ems_vue/emp/delete?id="+id).then(res=>{
						if(res.data.state){
							alert(res.data.msg+"点击确定刷新数据");
							_this.findAll();  //重新加载数据
						}else{
							alert(res.data.msg);
						}
					});
				}

			},

			//查询员工信息列表的方法
			findAll(){
				var _this = this;
				axios.get("http://localhost:8080/ems_vue/emp/findAll").then(res=>{
					_this.emps = res.data;
				});

			}
		},

		created() {
			var _this = this;
			var userString = localStorage.getItem("user");
			_this.time = new Date();

			if(userString){
				var Luser = JSON.parse(userString);
				this.user = Luser;
			}else{
				alert("您尚未登录,点击确定跳转至登录");
				location.href="/ems_vue/login.html";
			}

			//查询所有信息

			this.findAll();

		}

	});
</script>

在展现用户列表时,我们呢只需要用到:findAll和Vue自身的生命周期函数created()即可

同样的,首先new 一个Vue的组件,并在data中生命了一个名为emp的数组,来用于接收我们数据。由于用户信息的渲染和页面的加载是同时进行的,因此,我们需要使用生命周期函数created()

我们在created()中进行了用户user的判断,以防止非法登录。在用户登录的时候,我们在用户的信息存储到了浏览器的localStorage,此时,我们便可以进行登录拦截。如果此时在localStorage没有用户的信息,那么本次请求将会被拦截。

如果localStorage存在用户信息,那么便会执行findAll()。同样的,我们在这里像后台发起一个axios请求。接收到后端传来的数据,这是我们便可以将数据渲染到页面中。

取数据时,是采用的Vue中的v-for指令。

后端接口

关于mapper和sql语句就不过多赘述

mapper层:

@Mapper
@Repository
public interface EmpMapper {

    List<Emp> getAllEmp();

    void save(Emp emp);

    void deleteEmp(String id);

    Emp findById(String id);

    void update(Emp emp);
}

EmpMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.feng.mapper.EmpMapper">

    <cache type="com.feng.cache.RedisCache"/>

    <!--findAll-->
    <select id="getAllEmp" resultType="Emp">
        select id,name,path,salary,age from t_emp
    </select>

    <insert id="save" parameterType="Emp" useGeneratedKeys="true" keyProperty="id">
        insert into emp.t_emp
         values (#{id},#{name},#{path},#{salary},#{age})
    </insert>

    <delete id="deleteEmp" parameterType="String">
        delete from emp.t_emp where id=#{id}
    </delete>

    <select id="findById" parameterType="String" resultType="Emp">
         select id,name,path,salary,age from t_emp where id=#{id}
    </select>

    <update id="update" parameterType="Emp">
        update emp.t_emp set name=#{name},path=#{path},salary=#{salary},age=#{age} where id=#{id};
    </update>

</mapper>

service层:

@Service
@Transactional
public class EmpServiceImpl implements EmpService{

    @Autowired
    private EmpMapper empMapper;

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public List<Emp> getAllEmp() {
        return empMapper.getAllEmp();
    }

    @Override
    public void save(Emp emp)
    {
        empMapper.save(emp);
    }

    @Override
    public void deleteEmp(String id)
    {
        empMapper.deleteEmp(id);
    }

    @Override
    public Emp findById(String id) {
        return empMapper.findById(id);
    }

    @Override
    public void update(Emp emp) {

        empMapper.update(emp);
    }
}

controller层:

@GetMapping("findAll")
public List<Emp> findAll()
{
    return empService.getAllEmp();
}

好像,这个业务并没有什么难点吧

员工添加

在员工添加

在员工的展现页面添加了一个超链接

<input type="button" class="button" value="Add Employee" onclick="location='addEmp.html'"/>

用于我们跳转到员工添加页面,具体的句法就不说了,之前说过了。

addEmp.html中的核心代码:

<h1>
   add Emp info:
</h1>
<form action="emplist.html" method="post">
   <table cellpadding="0" cellspacing="0" border="0" class="form_table">

      <tr>
         <td valign="middle" align="right">
            name:
         </td>
         <td valign="middle" align="left">
            <input type="text" v-model="emp.name" class="inputgri" name="name" />
         </td>
      </tr>

      <tr>
         <td valign="middle" align="right">
            photo:
         </td>
         <td valign="middle" align="left">
            <input type="file" ref="myPhoto" name="photo" />
         </td>
      </tr>

      <tr>
         <td valign="middle" align="right">
            salary:
         </td>
         <td valign="middle" align="left">
            <input type="text" v-model="emp.salary" class="inputgri" name="salary" />
         </td>
      </tr>

      <tr>
         <td valign="middle" align="right">
            age:
         </td>
         <td valign="middle" align="left">
            <input type="text " v-model="emp.age" class="inputgri" name="age" />
         </td>
      </tr>

   </table>
   <p>
      <input type="button" @click="saveEmp" class="button" value="Confirm" />
   </p>
</form>
<!--引入Vue相关的JS-->
<script src="/ems_vue/js/vue.js"></script>
<script src="/ems_vue/js/axios.min.js"></script>
<script>
	var app = new Vue({
		el: "#wrap",
		data: {
			user: {}, //用来保存用户登录的信息
			emp: {

			}
		},
		methods: {

			//安全退出
			logout(){
				localStorage.removeItem("user");
				location.reload(true);  //刷新页面
			},

			//保存员工信息
			saveEmp(){
				console.log(this.emp);
				console.log(this.$refs.myPhoto.files[0]);  //获取文件信息
				//文件上传时,请求方式必须时post  enctype必须为multipart/form-data
				let formData = new FormData();
				formData.append("name",this.emp.name);
				formData.append("salary",this.emp.salary);
				formData.append("age",this.emp.age);
				formData.append("photo",this.$refs.myPhoto.files[0]);
				var _this = this;
				axios({
					method: "post",
					url: "http://localhost:8080/ems_vue/emp/save",
					data: formData,
					headers: {
						'content-type': 'multipart/form-data'
					}
				}).then(res=>{
					console.log(res.data);
					if(res.data.state){
						if(window.confirm(res.data.msg+",点击确定跳转到列表页")){
							location.href="/ems_vue/emplist.html"
						}else{
							_this.emp = {};
						}
					}else{
						alert(res.data.msg);
					}
				});
			}

		},

		created() {
			var userString = localStorage.getItem("user");

			if(userString){
				var Luser = JSON.parse(userString);
				this.user = Luser;
			}else{
				alert("您尚未登录,点击确定跳转至登录");
				location.href="/ems_vue/login.html";
			}

		}

	});
</script>

同样的方式,我们new 一个vue组件,并声明了一个emp的对象数据,用来保存我们要添加的数据。和用户注册一样,首先通过v-model进行了数据双向绑定。

在这里我们主要重点说的是关于员工头像的保存和传输。在图片上传中,并没有采用Vue中的双向绑定。当时我们在Vue中使用文件上传的功能,我们需要把相关文件绑定给Vue中的ref

文件上传时,请求方式必须时post enctype必须为multipart/form-data

此时,我们只能通过axios的构造函数,进行配置axios请求

axios({
    method: "post",
    url: "http://localhost:8080/ems_vue/emp/save",
    data: formData,
    headers: {
        'content-type': 'multipart/form-data'
    }
}).then(res=>{
    console.log(res.data);
    if(res.data.state){
        if(window.confirm(res.data.msg+",点击确定跳转到列表页")){
            location.href="/ems_vue/emplist.html"
        }else{
            _this.emp = {};
        }
    }else{
        alert(res.data.msg);
    }
});

这样的请求方式实际上还是采用表单提交的方式,因此我们需要构架一个表单对象,

let formData = new FormData();
formData.append("name",this.emp.name);
formData.append("salary",this.emp.salary);
formData.append("age",this.emp.age);
formData.append("photo",this.$refs.myPhoto.files[0]);
var _this = this;

这里的formdata模拟的就是一个表单,我们可以向formdata中appenpd emp的信息。这样我们就可以进行数据的传输了。

mapper层、service在上面。

controller层:

@Value("${photo.dir}")
private String realPath;
//保存员工信息
@PostMapping("save")
public Map<String,Object> save(Emp emp, MultipartFile photo){
    log.info("员工信息:[{}]",emp.toString());
    log.info("头像信息:[{}]",photo.getOriginalFilename());
    Map<String, Object> map = new HashMap<>();

    try {
        //头像的保存
        String newFileName = UUID.randomUUID().toString()+"."+ FilenameUtils.getExtension(photo.getOriginalFilename());
        photo.transferTo(new File(realPath,newFileName));

        //设置头像地址
        emp.setPath(newFileName);

        //保存员工信息
        empService.save(emp);
        map.put("state",true);
        map.put("msp","员工信息保存成功");
    } catch (Exception e) {
        e.printStackTrace();
        map.put("msg","员工信息保存失败");
    }

    return map;
}

在这里我们需要注意的就是关于文件的保存。首先我们需要在配置文件中声明一个文件的上传的目录。

# 提供web资源访问功能
spring.web.resources.static-locations=classpath:/static/,file:${photo.dir}

# 必须是根目录
photo.dir=D:\\JavaProject\\ems_vue\\src\\main\\resources\\static\\photos  

为了避免用户头像的文件名一致,我们需要修改文件名,

  //头像名称修改
String newFileName = UUID.randomUUID().toString()+"."+FilenameUtils.getExtension(photo.getOriginalFilename());

新的文件名我们使用的是一个UUID的方式。

getExtension():获取文件的扩展名

用户头像的保存:

transferTo,指定文件的上传,参数是一个File对象,指定了上传的路径和上传的文件名

photo.transferTo(new File(realPath,newFileName));

好了,其他的就不需要说明了。

用户更新

<td>
<a :href="'/ems_vue/updateEmp.html?id='+emp.id">update emp</a>
</td>

updateEmp.html核心代码

<tr>
         <td valign="middle" align="right">
            old photo:
         </td>
         <td valign="middle" align="left">
            <img :src="'/ems_vue/'+emp.path" style="height: 60px;">
         </td>
      </tr>

      <tr>
         <td valign="middle" align="right">
            name:
         </td>
         <td valign="middle" align="left">
            <input type="text" v-model="emp.name" class="inputgri" name="name"/>
         </td>
      </tr>
      <tr>
         <td valign="middle" align="right">
            photo:
         </td>
         <td valign="middle" align="left">
            <input type="file" ref="photo" name="photo" />
         </td>
      </tr>
      <tr>
         <td valign="middle" align="right">
            salary:
         </td>
         <td valign="middle" align="left">
            <input type="text" class="inputgri" name="salary" v-model="emp.salary"/>
         </td>
      </tr>
      <tr>
         <td valign="middle" align="right">
            age:
         </td>
         <td valign="middle" align="left">
            <input type="text" class="inputgri" name="age"v-model="emp.age"/>
         </td>
      </tr>
   </table>
   <p>
      <input type="button" @click="editEmp" class"button" value="Confirm" />
   </p>
</form>

<!--引入Vue相关的JS-->
<script src="/ems_vue/js/vue.js"></script>
<script src="/ems_vue/js/axios.min.js"></script>
<script>
	var app = new Vue({
		el: "#wrap",
		data: {
			user: {}, //用来保存用户登录的信息
			emp: {

			}
		},
		methods: {

			//安全退出
			logout(){
				localStorage.removeItem("user");
				location.reload(true);  //刷新页面
			},

			//处理员工信息的修改
			editEmp(){
				console.log(this.emp);
				console.log(this.$refs.photo.files[0]);
				//文件上传时,请求方式必须时post  enctype必须为multipart/form-data
				let formData = new FormData();
				formData.append("id",this.emp.id);
				formData.append("name",this.emp.name);
				formData.append("path",this.emp.path);
				formData.append("salary",this.emp.salary);
				formData.append("age",this.emp.age);
				formData.append("photo",this.$refs.photo.files[0]);
				var _this = this;
				axios({
					method: "post",
					url: "http://localhost:8080/ems_vue/emp/update",
					data: formData,
					headers: {
						'content-type': 'multipart/form-data'
					}
				}).then(res=>{
					console.log(res.data);
					if(res.data.state){
						if(window.confirm(res.data.msg+",点击确定跳转到列表页")){
							location.href="/ems_vue/emplist.html"
						}
					}else{
						alert(res.data.msg);
					}
				});
			}

		},

		created() {
			var userString = localStorage.getItem("user");

			if(userString){
				var Luser = JSON.parse(userString);
				this.user = Luser;
			}else{
				alert("您尚未登录,点击确定跳转至登录");
				location.href="/ems_vue/login.html";
			}

			//获取对应的id信息
			var start = location.href.lastIndexOf("=");
			var id  = location.href.substring(start+1);
			console.log(id);
			//查询一个人信息
			axios.get("http://localhost:8080/ems_vue/emp/findById?id="+id).then(res=>{
				var _this = this;
				_this.emp = res.data;
				console.log(res.data);
			});
		}

	});
</script>

更新操作类似于添加用户操作一样,我们只需要注意传递用户id以及回显响相应用户信息的操作。

在跳转页面时,将请求的id也传递过去,这样我们便可以在渲染页面的时候向后台发送一个带有id的参数的axios请求,后台根据id查询要修改的用户,渲染页面的同时回显要更新的用户信息。

此时我们便可以进行对用户信息的更改了,这里便也不在多说了。操作和添加操作一致。

后端接口

同样的mapper层和service层不在重复说了。

controller层:

//查询用户,回显信息
@GetMapping("findById")
public Emp findById(String id)
{
    log.info("查询员工信息的id:[{}]",id);
    return empService.findById(id);
}
//更新用户信息
@PostMapping("update")
public Map<String,Object> update(Emp emp,MultipartFile photo)
{
    log.info("员工信息:[{}]",emp.toString());

    Map<String, Object> map = new HashMap<>();
    try {
        if(photo != null && photo.getSize() != 0)
        {
            log.info("头像信息:[{}]",photo.getOriginalFilename());
            //头像的保存
            String newFileName = UUID.randomUUID().toString()+"."+ FilenameUtils.getExtension(photo.getOriginalFilename());
            photo.transferTo(new File(realPath,newFileName));

            //设置头像地址
            emp.setPath(newFileName);
        }
        //保存员工信息
        empService.update(emp);
        map.put("state",true);
        map.put("msp","员工信息保存成功");
    } catch (Exception e) {
        e.printStackTrace();
        map.put("msg","员工信息保存失败");
    }

    return map;
}

在这里我们需要注意一点,如果照片为空的话,那样我们就不需要重新设置图片的地址了,这样能够提高我们的效率。

删除用户

<a href="javascript:;" @click="delEmp(emp.id)">delete emp</a>

这里的href并不是要给具体超链接地址了。

javascript:;:代表了当我们开始点击这个button时,此时会执行一个代码块,也是就delEmp,同时我们需要传递一个id属性。

//删除员工
delEmp(id){
   if(window,confirm("确定要删除这条员工信息吗")){
      var _this = this;
      axios.get("http://localhost:8080/ems_vue/emp/delete?id="+id).then(res=>{
         if(res.data.state){
            alert(res.data.msg+"点击确定刷新数据");
            _this.findAll();  //重新加载数据
         }else{
            alert(res.data.msg);
         }
      });
   }

},

这里也不讲太多了,没有什么重要的知识了。

当然,还有一个退出的操作,这里就不贴出来,大家能否写出是怎么实现的吗?

添加Redis

添加依赖

<!--redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

添加redis的配置

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
@Slf4j
public class RedisCache implements Cache {

    private String id;
    @Autowired
    private RedisTemplate redisTemplate;

    public RedisCache(String id) {
        log.info("放入缓存的信息:[{}]",id);
        this.id = id;
    }

    @Override
    public String getId() {
        return this.id;
    }

    @Override
    //放入redis缓存
    public void putObject(Object key, Object value)
    {
        log.info("放入缓存的key:[{}] 放入缓存的value[{}]",key,value);

        getRedisTemplate().opsForHash().put(id,key.toString(),value);

    }

    @Override
    //获取缓存
    public Object getObject(Object key) {

        log.info("获取缓存的key:[{}]",key.toString());

        return getRedisTemplate().opsForHash().get(id,key.toString());
    }

    @Override
    //删除指定缓存
    public Object removeObject(Object o) {
        return null;
    }

    @Override
    public void clear() {
        log.info("清楚所有缓存");
        getRedisTemplate().delete(id);
    }

    @Override
    public int getSize() {
        return getRedisTemplate().opsForHash().size(id).intValue();
    }

    //封装获取redisTemplate
    public RedisTemplate getRedisTemplate()
    {
        RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

首先,我们需要实现Mybatis中的Cache接口,但是由于这个对象不是有Spring 工厂构建的,所以我们不用通过Spring的自动注入的方式获取到redisTemplate,因此我们需要开发一个工具类,用来获取到redisTemplate。

@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        this.applicationContext = applicationContext;
    }

    public static Object getBean (String name)
    {
        return applicationContext.getBean(name);
    }
}

当我们实现了ApplicationContextAware这个接口后,它会将Springboot自动创建好的工厂给我们。通过这个工具类,我们便可以拿到redisTemplate。

结束

这次的总结到了这里也就该结束了。有什么问题不妨可以留个言。或者有什么好的想法可以评论出来。一起进步

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值