需要项目源码请点赞关注收藏后评论区留言并且私信~~~
一、项目简介
前后端分离的核心思想时前端页面通过掉用后端的RESTfulApI进行数据交互。本次项目使用Spring Boot+Spring Data JPA实现后端系统,使用Vue.js实现前端系统,数据库采用mysql,集成开发环境为Intellij IDEA
二、名片系统功能介绍
名片系统是针对注册用户使用的系统 有以下几种功能
1:非注册用户可以注册为注册用户
2:成功注册的用户可以登录系统
3:成功登录的用户,可以添加,修改,删除以及浏览自己客户的名片信息
三、构建后端系统cardmis
1:修改pom.xml
添加mysql依赖和热部署依赖 具体代码如下
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ch</groupId> <artifactId>cardmis</artifactId> <version>0.0.1-SNAPSHOT</version> <name>cardmis</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> <!-- 热部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2:配置数据源信息
在配置文件application.properties中 配置端口号 数据源以及文件上传等信息
server.port=8443 ### ##数据源信息配置 ### #数据库地址 spring.datasource.url=jdbc:mysql://localhost:3306/card?characterEncoding=utf8 #数据库用户名 spring.datasource.username=root #数据库密码 spring.datasource.password=root #数据库驱动 spring.datasource.driver-class-name=com.mysql.jdbc.Driver #要导入驱动包 #数据库MySQL为8.x时,驱动类为com.mysql.cj.jdbc.Driver #### #JPA持久化配置 #### #指定数据库类型 spring.jpa.database=MYSQL #指定是否在日志中显示SQL语句 spring.jpa.show-sql=true #指定自动创建、更新数据库表等配置,update表示如果数据库中存在持久化类对应的表就不创建, #不存在就创建对应的表 spring.jpa.hibernate.ddl-auto=update #上传文件时,默认单个上传文件大小是1MB,max-file-size设置单个上传文件大小 spring.servlet.multipart.max-file-size=50MB #默认总文件大小是10MB,max-request-size设置总上传文件大小 spring.servlet.multipart.max-request-size=500MB
3:创建持久化实体类
根据名片系统功能可知,名片系统一共有两个实体:用户和卡片,并且是一对多的关系,因此后端系统的持久化实体类一共有两个 分别为UserEntitiy和CardEntity
用户实体类代码如下
package com.ch.cardmis.entity; import java.util.List; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @Entity @Table(name = "user_table") @JsonIgnoreProperties(value = { "hibernateLazyInitializer"}) public class UserEntity implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id;//主键 private String uname; private String upwd; //名片列表,用户与名片是一对多的关系 @OneToMany( mappedBy = "user", cascade=CascadeType.ALL, targetEntity = CardEntity.class, fetch=FetchType.LAZY ) private List<CardEntity> cardEntityList; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public String getUpwd() { return upwd; } public void setUpwd(String upwd) { this.upwd = upwd; } public List<CardEntity> getCardEntityList() { return cardEntityList; } public void setCardEntityList(List<CardEntity> cardEntityList) { this.cardEntityList = cardEntityList; } }
卡片实体类代码如下
package com.ch.cardmis.entity; import java.io.Serializable; import javax.persistence.*; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @Entity @Table(name = "card_table") @JsonIgnoreProperties(value = { "hibernateLazyInitializer"}) public class CardEntity implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id;//主键 private String name; private String telephone; private String email; private String company; private String post; private String address; private String logo; //所属用户,名片与用户是多对一的关系 @ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=false) //可选属性optional=false,表示用户不能为空。删除名片,不影响用户 @JoinColumn(name="id_user_id")//设置在card_table表中的关联字段(外键) @JsonIgnore private UserEntity user; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTelephone() { return telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public String getPost() { return post; } public void setPost(String post) { this.post = post; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getLogo() { return logo; } public void setLogo(String logo) { this.logo = logo; } public UserEntity getUser() { return user; } public void setUser(UserEntity user) { this.user = user; } }
4:创建Repository持久层
后端系统的数据访问是基于Spring Data JPA的,数据访问接口需要继承Repository接口,与持久化实体类一样,同样有用户和卡片两个数据访问接口
用户访问接口代码如下
package com.ch.cardmis.repository; import com.ch.cardmis.entity.UserEntity; import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<UserEntity, Integer> { /** * 查询用户名是否已存在 */ public UserEntity findByUname(String uname); /** *登录 */ public UserEntity findByUnameAndUpwd(String uname, String upwd); }
卡片访问接口代码如下
package com.ch.cardmis.repository; import com.ch.cardmis.entity.CardEntity; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface CardRepository extends JpaRepository<CardEntity, Integer> { //根据用户id查询该用户的名片 public List<CardEntity> findByUser_id(Integer id, Sort sort); }
5:创建业务层
在Spring框架中 提倡使用接口,因此在业务层中涉及Service接口和Service实现类 代码如下
卡片实现类
package com.ch.cardmis.service; import com.ch.cardmis.entity.CardEntity; import com.ch.cardmis.entity.UserEntity; import com.ch.cardmis.repository.CardRepository; import com.ch.cardmis.util.MyUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpSession; import java.io.File; @Service public class CardServiceImpl implements CardService { @Autowired private CardRepository cardRepository; @Override public String add(CardEntity cardEntity, HttpSession session, MultipartFile file) { if("noLogin".equals(isLogin(session))){ return "noLogin"; }else{ UserEntity user = (UserEntity)session.getAttribute("user"); cardEntity.setUser(user); //防止文件名重名 String newFileName = ""; if(file != null){ String fileName = file.getOriginalFilename(); newFileName = MyUtil.getNewFileName(fileName); String realpath = "C:\\Users\\ChenHeng\\IdeaProjects\\cardmis-vue\\cardmis-vue\\static"; File targetFile = new File(realpath, newFileName); if(!targetFile.exists()){ targetFile.mkdirs(); } //设置文件名 cardEntity.setLogo("static/" + newFileName); //上传 try { file.transferTo(targetFile); } catch (Exception e) { e.printStackTrace(); } } cardRepository.save(cardEntity); return "ok"; } } @Override public Object cards(HttpSession session) { if("noLogin".equals(isLogin(session))){ return "noLogin"; }/* else { Sort sort = new Sort(Sort.Direction.DESC, "id"); UserEntity user = (UserEntity)session.getAttribute("user"); return cardRepository.findByUser_id(user.getId(), sort); } */ return null; } @Override public String delete(HttpSession session,Integer cid) { if("noLogin".equals(isLogin(session))){ return "noLogin"; }else { cardRepository.deleteById(cid); return "ok"; } } @Override public Object aCard(HttpSession session, Integer cid) { if("noLogin".equals(isLogin(session))){ return "noLogin"; }else { return cardRepository.getOne(cid); } } @Override public String isLogin(HttpSession session) { Object user = session.getAttribute("user"); if(user == null) return "noLogin"; return "yes"; } }
用户实现类
package com.ch.cardmis.service; import com.ch.cardmis.entity.UserEntity; import com.ch.cardmis.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpSession; @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Override public String register(UserEntity requestUser) { UserEntity ue = userRepository.findByUname(requestUser.getUname()); if(ue != null) return "no"; else{ userRepository.save(requestUser); return "yes"; } } @Override public String login(UserEntity requestUser, HttpSession session) { UserEntity ue = userRepository.findByUnameAndUpwd(requestUser.getUname(), requestUser.getUpwd()); if(ue != null){//登录成功 session.setAttribute("user", ue); return "ok"; } return "no"; } }
6:创建控制器层
卡片控制器
package com.ch.cardmis.controller; import com.ch.cardmis.entity.CardEntity; import com.ch.cardmis.service.CardService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpSession; @RestController public class CardController { @Autowired private CardService cardService; @CrossOrigin//跨域访问 @PostMapping(value = "cardmis/add") public String add(CardEntity cardEntity, HttpSession session, MultipartFile file) { return cardService.add(cardEntity, session, file); } @CrossOrigin//跨域访问 @GetMapping(value = "cardmis/cards") public Object cards(HttpSession session) { return cardService.cards(session); } @CrossOrigin//跨域访问 @PostMapping(value = "cardmis/delete") public String delete(HttpSession session,Integer cid) { return cardService.delete(session,cid); } @CrossOrigin//跨域访问 @GetMapping(value = "cardmis/aCard") public Object aCard(HttpSession session,Integer cid) { return cardService.aCard(session,cid); } }
用户控制器
package com.ch.cardmis.controller; import com.ch.cardmis.entity.UserEntity; import com.ch.cardmis.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpSession; @RestController public class UserController { @Autowired private UserService userService; @CrossOrigin//跨域访问 @PostMapping(value = "cardmis/register") public String register(@RequestBody UserEntity requestUser) { return userService.register(requestUser); } @CrossOrigin//跨域访问 @PostMapping(value = "cardmis/login") public String login(@RequestBody UserEntity requestUser, HttpSession session) { return userService.login(requestUser, session); } }
7:创建跨域响应头设置过滤器
8:创建工具类
后端系统项目目录结构如下
后面几个类代码省略不表 有需要请点赞关注收藏后评论区留言并且私信
四、构建前端系统cardmis-vue
Node.js与Vue.js的部署请参考我这篇博客 此处不再赘述
项目结构目录如下
开发前端页面
在开发的时候,前端用前端的服务器开发,后端用后端的服务器开发。当开发前端内容时,可以把前端的请求通过前端服务器转发给后端,即可实现观察结果,并且不需要知道后端怎么实现,而只需要知道接口提供的功能,前后端的开发人员各司其职
部分Vue代码如下
<template> <div class="active"> <NavMain></NavMain> <h3>添加名片</h3> <form> 姓名:<input type="text" v-model="name" placeholder="请输入用户名"/><br><br> 电话:<input type="text" v-model="telephone" placeholder="请输入电话"/><br><br> 邮箱:<input type="text" v-model="email" placeholder="请输入邮箱"/><br><br> 单位:<input type="text" v-model="company" placeholder="请输入单位"/><br><br> 邮编:<input type="text" v-model="post1" placeholder="请输入邮编"/><br><br> 地址:<input type="text" v-model="address" placeholder="请输入地址"/><br><br> 头像: <input type="file" @change="getFile($event)"/><br><br> <button type="button" @click="add($event)" :disabled="isDisable">添加</button> <button type="reset">重置</button> </form> <br> </div> </template> <script> import NavMain from '@/components/NavMain' export default { name: 'Add', components: {NavMain}, data () { return { isDisable:false } }, methods: { //获得文件对象 getFile(event) { this.file = event.target.files[0]; }, add (event) { this.isDisable = true; event.preventDefault(); let formData = new FormData(); formData.append('name', this.name === undefined ? '': this.name); formData.append('telephone', this.telephone === undefined ? '': this.telephone); formData.append('email', this.email === undefined ? '': this.email); formData.append('company', this.company === undefined ? '': this.company); formData.append('post', this.post1 === undefined ? '': this.post1); formData.append('address', this.address === undefined ? '': this.address); formData.append('file', this.file === undefined ? null: this.file); let config = { headers:{'Content-Type':'multipart/form-data'} }; this.$axios .post('/add', formData, config)//直接提交表单 .then(successResponse => { if (successResponse.data === "ok") { alert("添加成功") this.$router.replace({path: '/main'}) }else if(successResponse.data === "noLogin"){ alert("没有登录,请登录!") this.$router.replace({path: '/login'}) }else { alert("添加失败") this.isDisable = false } }) .catch(failResponse => { alert("响应异常") }) } } } </script> <style> .active { background-image: url("../assets/bb.jpg"); } </style>
同样还有修改路由配置,使用钩子函数判断是否登录等操作 此处不再赘述
五、测试效果
首先运行后端系统cardmis的主类,然后再启动前端系统cardmis-vue的主类 通过访问
https://localhost:8080/测试运行 效果如下
首页如下
登录界面如下 会自动查询mysql数据库中有无匹配记录
注册界面如下 新用户可以先注册
主页面显示已有的名片信息
同时可以实现基本的增删改查功能
创作不易 觉得有帮助请点赞关注收藏~~~