SpringDataJPA+SpringBoot+Swagger2+vue.js前后端分离实现基本CURD

Vue.js 是什么

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

vue.js官网 ==> https://cn.vuejs.org/

vue.js菜鸟教程学习文档 ==> https://www.runoob.com/vue2/vue-tutorial.html

Swagger 官网 ==> https://swagger.io/

Swagger 2简介

它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档。它既可以减少我们创建文档的工作量,同时说明内容又整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API。

话不多说开始撸码

先导入pom.xml依赖


<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.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.1.5.RELEASEversion>
        <relativePath/> 
    parent>
    <groupId>com.zhaoleigroupId>
    <artifactId>jpa-swagger-vueartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>jpa-swagger-vuename>
    <description>Demo project for Spring Bootdescription>

    <properties>
        <java.version>1.8java.version>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-jpaartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jdbcartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-thymeleafartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
            <scope>runtimescope>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <scope>runtimescope>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
		
		
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger2artifactId>
            <version>2.8.0version>
        dependency>
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger-uiartifactId>
            <version>2.8.0version>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>

(注意导入swagger2相关的依赖)
pojo实体类

package com.zhaolei.jpaswaggervue.pojo;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;

/**
 * @author 15579
 * 2019/6/3 14:09
 * 文件说明:Student实体类
 */
@Data
@Table
@Entity //数据库没有此实体类对应的表就会自动生成
public class Student implements Serializable {
    //自动增长
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String name;

    @Column
    private String sex;
    
    @Column
    private  Integer gradeId;
}

Dao层

package com.zhaolei.jpaswaggervue.dao;

import com.zhaolei.jpaswaggervue.pojo.Student;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

/**
 * @author 15579
 * 2019/6/3 14:21
 * 文件说明:StudentDao层
 */
@Repository
public interface StudentDao extends JpaRepository<Student,Integer>, JpaSpecificationExecutor<Student>{
    //nativeQuery =true 表示这是原生SQL
    @Query(value = "SELECT * from student where `name` like concat('%',?,'%')",nativeQuery = true)
    Page<Student> findLikeNameByPage(String name, Pageable pageable);
}

Service层

package com.zhaolei.jpaswaggervue.service;

import com.zhaolei.jpaswaggervue.pojo.Student;
import org.springframework.data.domain.Page;

import java.util.List;

/**
 * @author 15579
 * 2019/6/4 14:26
 * 文件说明:
 */
public interface StudentService {
    /**
     * 新增学生信息
     * @param student
     * @return
     */
    Student save(Student student);

    /**
     * 修改
     * @param student
     * @return
     */
    Student update(Student student);

    /**
     * 删除学生
     * @param id
     */
    void deleteStu(Integer id);

    /**
     * 分页查询
     * @param pageNum
     * @param pageSize
     * @return
     */
    Page<Student> findByPage(Integer pageNum, Integer pageSize, Student student);

    /**
     * 根据编号查询
     * @param id
     * @return
     */
    Student findStudentById(Integer id);
}

impl层

package com.zhaolei.jpaswaggervue.service.impl;

import com.zhaolei.jpaswaggervue.dao.StudentDao;
import com.zhaolei.jpaswaggervue.pojo.Student;
import com.zhaolei.jpaswaggervue.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author 15579
 * 2019/6/4 14:27
 * 文件说明:
 */
@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentDao studentDao;

    /**
     * 新增学生信息
     *
     * @param student
     * @return
     */
    @Override
    public Student save(Student student) {
        return studentDao.save(student);
    }

    /**
     * 修改
     *
     * @param student
     * @return
     */
    @Override
    public Student update(Student student) {
        return studentDao.save(student);
    }

    /**
     * 删除学生
     *
     * @param id
     */
    @Override
    public void deleteStu(Integer id) {
        studentDao.deleteById(id);
    }

    /**
     * 分页查询
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<Student> findByPage(Integer pageNum, Integer pageSize,Student student) {
        if(pageNum==null||pageNum==0){
            pageNum=1;
        }
        if(pageSize==null||pageSize==0){
            pageSize=2;
        }
//        第一种方式模糊查询并且分页
//        ExampleMatcher matcher = ExampleMatcher.matching()
//                .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.startsWith())//模糊查询匹配开头,即{username}%
//                .withIgnorePaths("sex")
//                .withIgnorePaths("id");
//        Example example = Example.of(student, matcher);

        PageRequest of=PageRequest.of(pageNum-1,pageSize);
        //第一种方式
        // Page page=studentDao.findAll(example,of);
        //第二种方式模糊查询并且分页
        Page<Student> page=studentDao.findLikeNameByPage(student.getName()==null?"":student.getName(),of);
        return page;
    }

    /**
     * 根据编号查询
     *
     * @param id
     * @return
     */
    @Override
    public Student findStudentById(Integer id) {
        return studentDao.findById(id).get();
    }
}

controller层

package com.zhaolei.jpaswaggervue.controller;

import com.zhaolei.jpaswaggervue.pojo.Student;
import com.zhaolei.jpaswaggervue.service.StudentService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

/**
 * @author 15579
 * 2019/6/3 14:28
 * 文件说明:Student控制层
 */
@RestController
@Api(value = "Swagger2 api 注释 Student控制层")
public class StuController {
    @Autowired
    private StudentService studentService;

    //根据条件分页查询
    @GetMapping("/findByPage")
    @ApiOperation(value = "分页查询",notes = "根据姓名模糊查询并分页")
    public Object findByPage(Integer pageNum, Integer pageSize, Student student){
        if(pageNum==null||pageNum<=0){
            pageNum=1;
        }
        Page<Student> page = studentService.findByPage(pageNum, pageSize,student);
       return  page;
    }

    //根据ID删除学生
    @DeleteMapping("/deleteStu")
    @ApiOperation(value = "删除",notes = "根据ID删除学生")
    public  int delteStu(@RequestParam("id") Integer id){
        System.out.println(id);
        try {
            studentService.deleteStu(id);
            return 1;
        }catch (Exception e){
            return 0;
        }
    }

    //修改学生信息
    @PutMapping("/updateStu")
    @ApiOperation(value = "修改",notes = "修改学生信息")
    public  Object updateStu(@RequestBody Student student){
        Student updStudent = studentService.update(student);
        return  updStudent;
    }

    //新增学生信息
    @PostMapping("/addStu")
    @ApiOperation(value = "新增",notes = "新增学生信息")
    public Object addStu(@RequestBody Student student){
        System.out.println(student.getName());
        Student save = studentService.save(student);
        return  save;
    }


    //跳转至编辑页面
    @GetMapping("/gotoEdit")
    @ApiOperation(value = "跳转至编辑页面",notes = "根据编号判断是修改还是新增")
    public String gotoEdit(Integer id,Model model){
        if(id!=null){
            //根据ID查询学生信息并显示在页面
            Student student = studentService.findStudentById(id);
            model.addAttribute("stu",student);
        }
        return "edit";
    }
}

然后编写swagger2的配置类

package com.zhaolei.jpaswaggervue.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.zhaolei.jpaswaggervue.controller"))//改成你项目的controller层路径
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Spring Boot中使用Swagger2实现前后端分离开发")
                .description("此项目只是练习如何实现前后端分离开发的小Demo")
                .termsOfServiceUrl("https://blog.csdn.net/weixin_44530530")
                .contact("***")
                .version("1.0")
                .build();
    }
}

注意:需要在SpringBoot项目的应用程序入口类中开启swagger2如下所示

package com.zhaolei.jpaswaggervue;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@EnableSwagger2      //开启swagger2 api接口文档
public class JpaSwaggerVueApplication {
    public static void main(String[] args) {
        SpringApplication.run(JpaSwaggerVueApplication.class, args);
    }
}

让后就可以启动我们的项目我的端口号是8080:浏览器输入
http://localhost:8080/swagger-ui.html
然后会出现如下页面就代表你的swagger2 ui 的api接口已经生成好了
SpringDataJPA+SpringBoot+Swagger2+vue.js前后端分离实现基本CURD_第1张图片

后端代码基本已经编写完毕接下来使用写前段页面接收后端返回的json数据
我前段使用的框架是vue.js 使用的软件是HbuilderX


<html>
	<head>
		<meta charset="utf-8" />
		<title>title>
	head>
	<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js">script>
	<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js">script>
	<body>
		<div id="app">
			<label>姓名:label>
			<input type="text" name="likeName" v-model="likeName" />
			<input type="button" v-on:click="findByPage(1)" value="查询"  />
			<table border="1" cellspacing="1" cellpadding="20">
				<tr>
					<th>编号th>
					<th>姓名th>
					<th>性别th>
					<th>年级th>
					<th>操作th>
				tr>
				<template v-for="stu in stuList">
					<tr>
						<td>{{stu.id}}td>
						<td>{{stu.name}}td>
						<td>{{stu.sex}}td>
						<td>{{stu.gradeId}}td>
						<td>
							<a href="javascript:void(0)" v-on:click="del(stu.id)">删除a>
							<a href="javascript:void(0)" v-on:click="edit(stu)">编辑a>
						td>
					tr>
				template>
			table>
			<template>
				<table>
					<tr>
						<td>
							编号:<input type="text" name="id" v-model="student.id" placeholder="编号无需自己填写" readonly="readonly" />
						td>
						<td>
							姓名:<input type="text" name="name" v-model="student.name" />
						td>
						<td>
							性别:<input type="text" name="sex" v-model="student.sex" />
						td>
						<td>
							年级:<input type="text" name="gradeId" v-model="student.gradeId" />
						td>
						<td>
							<input type="button" value="保存" v-on:click="add(student)" />
						td>
					tr>
				table>
			template>
			<a href="javascript:void(0)" v-on:click="findByPage(1)">首页a>
			<a href="javascript:void(0)" v-on:click="findByPage(page.number)">上一页a>
			<a href="javascript:void(0)" v-on:click="findByPage(page.number+2)">下一页a>
			<a href="javascript:void(0)" v-on:click="findByPage(page.totalPages)">尾页a>
			当前第<span v-text="page.number+1">span>页/共{{page.totalPages}}页
		div>
	body>
		
		<script>
		var app = new Vue({
			el: "#app",
			data: {
				likeName:"",
				student: {
					id: "",
					name: "",
					sex: "",
					gradeId: ""
				},
				stuList: [],
				page:{}
			},
			methods: {
				findByPage: function(pageNum) {
					var _this = this;
					var likeName=this.likeName;
					if(pageNum!=null||pageNum!=''){
						if(pageNum>_this.page.totalPages){
							pageNum=_this.page.totalPages
						}
					}
					axios.get('http://localhost:8080/findByPage', {
							params: {
								pageNum: pageNum,
								name: likeName
							}
						})
						.then(function(response) {
							console.log(response.data)
							_this.page=response.data;
							_this.stuList = response.data.content;
						})
						.catch(function(error) { // 请求失败处理
							console.log(error);
						});
				},
				del: function(id) {
					var _this = this;
					console.log(id)
					let delId = id;
					axios.delete('http://localhost:8080/deleteStu', {
							params: {
								id: delId
							}
						})
						.then(function(response) {
							console.log(response.data)
							if (response.data == 1) {
								_this.findByPage();
								alert("删除成功");
							}
						})
						.catch(function(error) { // 请求失败处理
							console.log(error);
						});
				},
				add: function(student) {
					var _this = this;
					console.log(student.id);
					if (student.id != null&&student.id !='') {
						var stu = JSON.stringify(student);
						axios.put('http://localhost:8080/updateStu',stu, {
								headers: {
									'Content-Type':'application/json;charset=utf-8'
								}
							})
							.then(function(response) {
								alert("修改成功")
								_this.findByPage();
								_this.student.id=null;
								_this.student.name=null;
								_this.student.sex=null;
								_this.student.gradeId=null;
							})
							.catch(function(error) { // 请求失败处理
								console.log(error);
							});

					} else {
						axios.post('http://localhost:8080/addStu',student, {
								headers: {
									'Content-Type':'application/json;charset=utf-8'
								}
							})
							.then(function(response) {
								alert("新增成功")
								_this.findByPage();
								_this.student.name=null;
								_this.student.sex=null;
								_this.student.gradeId=null;
							})
							.catch(function(error) { // 请求失败处理
								console.log(error);
							});
					}
				},
				edit: function(student) {
					this.student = student;
				}
			},
			// 钩子 在Vue创建时就运行
			created: function() {
				this.findByPage();
			}
		})
	script>
html>

注意:

  1. 对象参数类型JSON化: data:JSON.stringify(object)
  2. 头部信息headers:“Content-Type”: “application/json; charset=UTF-8”
  3. controller层中请求方式写为POST
  4. 后台controller中获得参数方式:@RequestBody String Object
  5. String转换为json:JSONObject accident=JSONObject.fromObject(newsObject);

保存ctrl+r选择浏览器运行 然后会发现页面数据出不来按F12会发现报错
SpringDataJPA+SpringBoot+Swagger2+vue.js前后端分离实现基本CURD_第2张图片
出现这个错误的原因是因为没有考虑到跨域问题,所以还需要在后端SpringBoot项目添加一个解决跨域问题的配置类代码如下:

package com.zhaolei.jpaswaggervue.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    //跨域配置
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            //重写父类提供的跨域请求处理的接口
            public void addCorsMappings(CorsRegistry registry) {
                //添加映射路径
                registry.addMapping("/**")
                        //放行哪些原始域
                        .allowedOrigins("*")
                        //是否发送Cookie信息
                        .allowCredentials(true)
                        //放行哪些原始域(请求方式)
                        .allowedMethods("GET", "POST", "PUT", "DELETE")
                        //放行哪些原始域(头部信息)
                        .allowedHeaders("*")
                        //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
                        .exposedHeaders("Header1", "Header2");
            }
        };
    }
}

然后重启项目并刷新页面
SpringDataJPA+SpringBoot+Swagger2+vue.js前后端分离实现基本CURD_第3张图片
数据出来了!问题完美解决so easy!打完收功!
最后附上后端git仓库地址:https://gitee.com/riven666/jpa-swagger-vue

你可能感兴趣的:(Spring全家桶,Swagger2,ui,vue.js,SpringDataJPA,前后端分离CURD)