Springboot结合Vue开发社团管理网页

3 篇文章 1 订阅

目录

前言

搭建Springboot框架

Springboot整合JDBC

Springboot整合MyBatis-plus

添加依赖

使用lombok

搭建Vue框架

Vue框架引入axios

Vue框架引入iView(可选)

Springboot与Vue的通信

Springboot整合Vue跨域解决


前言

这个网页是一个社团管理网页,是一个毕设,设计的技术比较简单,写这个博客主要是一个回忆整理的过程,如果有更好的实现可以在评论区告知。如果发现过程有所错误,也请不吝斧正。

代码在最后

中间过程只是一些测试的代码

我的后台部分技术也是做这次毕设才第一次接触的,非常感谢一个大佬的指导,大佬在简书上也发表一些技术类文章,感兴趣的可以看一下。此处附上这位大佬的其中一篇文章地址。

https://www.jianshu.com/p/42989805b831

 

搭建Springboot框架

后台开发工具:IDEA(我用的版本是IntelliJ IDEA 2019.2.3 x64)

IDEA配置tomcat

IDEA配置maven

以上两个配置百度一下就有很多教程,可以按照教程走。

完成后如下图:

可以直接删除

 

新建一个controller文件夹,新建一个HelloWorld.java,测试一下

可以在浏览器输入localhost:8080/hello  就可以看到有Hello World的输出

Springboot整合JDBC

我用的是MySQL数据库,用的Navicat

删除resources文件夹里的 application.properties文件,新增application.yml文件

往里面写入数据库的配置信息

#配置DataSourceSpring
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/你的数据库的名字?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
    username: root
    password: 你的数据库密码
    initialSize: 5
    maxActive: 100
    minIdle: 3
    maxWait: 50000
  main:
    banner-mode: "off"

测试连接:

在test里写入

@SpringBootTest
class StoryApplicationTests {

    @Autowired
    private DataSource dataSource;

    @Test
    public void contextLoads() {
        System.out.println("---------------##--------------------");
        System.out.println("dataSource类型:"+dataSource.getClass());
        System.out.println("connection连接:"+dataSource.getConnection());
    }

}

运行,可以看到输出:

 

 

Springboot整合MyBatis-plus

添加依赖

可以去这个网址下依赖  https://mvnrepository.com/

mybatis-plus

连接池 druid

在pom.xml文件里写入

        <!-- mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
        <!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.22</version>
        </dependency>

字段的含义可以参见 mybatis-plus 官方手册(虽然我看了就忘记了,也不知道为什么写这些)https://mp.baomidou.com/guide/

#mybatis-plus
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  typeAliasesPackage: com.claire.bean
  global-config:
    field-strategy: not_empty
    column-underline: true
    capital-mode: true
    logic-delete-value: 1
    logic-not-delete-value: 0
    db-type: mysql
    refresh: true
    cache-enabled: false

 

使用lombok

pom.xml增加依赖

        <!--  lombok  -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>

 

新建一个common文件夹,创建如图六个文件,主要作用是统一规范返回的信息。使得返回的信息不是单一的数据,而是包含状态码的对象。 ClaireConstat是一个产量类。

 

新建文件夹bean(存放我们的实体类,与数据库表对应)

 

stories

package com.claire.bean;

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 com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * @author Claire
 */
@TableName("stories")
@Data
public class Stories implements Serializable {

    /**
     * 故事ID
     */
    @TableId(type = IdType.AUTO)
    private Integer sId;

    /**
     * 故事名称
     */
    private String sTitle;

    /**
     * 故事作者
     */
    private String sAuthor;

    /**
     * 故事内容
     */
    private  String content;

    /**
     * 故事简介
     */
    private String summary;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField("create_time")
    private LocalDateTime createTime;

}

新增mapper包、service包,还有一个工具类包utils,新增下面的文件

DataUtils

package com.claire.utils;
import org.springframework.util.StringUtils;

/**
 * @author Claire
 * 判断数据非空等
 */
public class DataUtils {

    /**
     * 判断字符串非空
     * @param originalStr
     * @return
     */
    public static boolean isNotEmptyStr(String originalStr){
        return !isEmptyStr(originalStr);
    }

    /**
     * 判断字符串为空
     * @param originalStr
     * @return
     */
    private static boolean isEmptyStr(String originalStr) {
        return StringUtils.isEmpty(originalStr);
    }

    /**
     * 判断对象为null
     * @param originalData
     * @return
     */
    public static boolean isNull(Object originalData){
        return originalData==null;
    }

    /**
     * 判断对象不为null
     * @param originalData
     * @return
     */
    public static boolean isNotNull(Object originalData){
        return !isNull(originalData);
    }

    /**
     * 判断两个对象是否相等
     * @param sourceData
     * @param targetData
     * @return
     */
    public static boolean isEqual(Object sourceData,Object targetData){
        return sourceData.equals(targetData);
    }

    /**
     * 判断两个对象是否不等
     * @param sourceData
     * @param targetData
     * @return
     */
    public static boolean isNotEqual(Object sourceData,Object targetData){
        return !isEqual(sourceData,targetData);
    }

    /**
     * 截取字符串一定长度
     * @param str
     * @param length
     * @return
     */
    public static String limitLength(String str,int length){
        if(isEmptyStr(str)){
            return str;
        }
        return str.length()>length?str.substring(0,length):str;
    }
}

在controller里增加ServiceController,目前的结构是,已经增加了一个获取数据库数据的函数,想尝试的话代码贴在下面

ApiCode

package com.claire.common;

/**
 * @author Claire
 */
public interface ApiCode<Enum> {
    public int getCode();
    public String getCodeMsg();
}

 

ApiResponse

package com.claire.common;

import lombok.Data;

/**
 * @author Claire
 */
@Data
public class ApiResponse<T> implements java.io.Serializable {

    /**
     * 状态码
     */
    private int code;

    /**
     * 错误消息
     */
    private String msg;

    /**
     * 消息响应的对象,比如列表
     */
    private T data;

    /**
     * 时间戳
     */
    private long time;

    public ApiResponse(){
        super();
    }

    public ApiResponse(ApiCode apiCode,String msg,T data){
        this.code=apiCode.getCode();
        this.msg=msg;
        this.data=data;
        this.time=System.currentTimeMillis();
    }

    public ApiResponse(ApiCode apiCode,T data){
        this.code= apiCode.getCode();
        this.msg=apiCode.getCodeMsg();
        this.data=data;
        this.time=System.currentTimeMillis();
    }

    public static ApiResponse success(Object data) {
        return new ApiResponse(BaseApiCode.SUCCESS, BaseApiCode.SUCCESS.getCodeMsg(), data);
    }

    public static ApiResponse success() {
        return new ApiResponse(BaseApiCode.SUCCESS, BaseApiCode.SUCCESS.getCodeMsg(), "");
    }


    public static ApiResponse failed(ApiCode code, String msg) {
        return new ApiResponse(code, msg, "");
    }

    public static ApiResponse failed(String msg) {
        return new ApiResponse(BaseApiCode.FAILED, msg, "");
    }

    public static ApiResponse failed() {
        return new ApiResponse(BaseApiCode.FAILED, BaseApiCode.FAILED.getCodeMsg(), "");
    }

    public static ApiResponse failed(Object data) {
        return new ApiResponse(BaseApiCode.FAILED, BaseApiCode.FAILED.getCodeMsg(), data);
    }
}

 

BaseApiCode

package com.claire.common;

/**
 * @author Claire
 */

public enum BaseApiCode implements ApiCode<Enum>{

    SUCCESS(0,"操作成功"),
    FAILED(-1,"操作失败"),
    SYSTEM_ERROR(500,"System Error"),
    VALID_ERROR(-1001,"验证失败"),
    OBJECT_NOT_EXISTS(-1003,"对象不存在"),
    NEED_LOGIN(401, "需要登录"),
    RESOURCE_NOT_FOUND(404, "Not Found");

    /**
     * 错误码
     */
    private int code;

    /**
     * 错误信息
     */
    private String codeMsg;

    private BaseApiCode(int code,String codeMsg){
        this.code=code;
        this.codeMsg=codeMsg;
    }

    @Override
    public int getCode() {
        return this.code;
    }

    @Override
    public String getCodeMsg() {
        return this.codeMsg;
    }
}

 

BaseApiCodeImp

package com.claire.common;

/**
 * @author Claire
 */
public class BaseApiCodeImp implements ApiCode {

    private Integer code;
    private String codeMsg;

    @Override
    public int getCode() {
        return this.code;
    }

    @Override
    public String getCodeMsg() {
        return this.codeMsg;
    }
}

 

BaseController

package com.claire.common;

/**
 * @author Claire
 */
public class BaseController {
    /**
     * 成功返回数据
     *
     * @return ApiResponse
     */
    protected ApiResponse success() {
        return ApiResponse.success();
    }

    /**
     * 成功返回数据
     *
     * @param data 待返回数据
     * @return ApiResponse
     */
    protected ApiResponse success(Object data) {
        return ApiResponse.success(data);
    }

    /**
     * 成功返回消息
     *
     * @param message 待返回成功消息
     * @return ApiResponse
     */
    protected ApiResponse success(String message) {
        return new ApiResponse(BaseApiCode.SUCCESS, message);
    }

    /**
     * 成功返回数据和消息
     *
     * @param message 待返回消息
     * @param data    带返回数据
     * @return ApiResponse
     */
    protected ApiResponse success(String message, Object data) {
        return new ApiResponse(BaseApiCode.SUCCESS, message, data);
    }

    /**
     * 失败返回
     *
     * @return ApiResponse
     */
    protected ApiResponse failed() {
        return ApiResponse.failed();
    }

    /**
     * 失败返回数据
     *
     * @param data 待返回数据
     * @return ApiResponse
     */
    protected ApiResponse failed(Object data) {
        return ApiResponse.failed(data);
    }

    /**
     * 失败返回消息
     *
     * @param message 待返回成功消息
     * @return ApiResponse
     */
    protected ApiResponse failed(String message) {
        return new ApiResponse(BaseApiCode.FAILED, message);
    }

    /**
     * 失败返回数据和消息
     *
     * @param message 待返回消息
     * @param data    带返回数据
     * @return ApiResponse
     */
    protected ApiResponse failed(String message, Object data) {
        return new ApiResponse(BaseApiCode.FAILED, message, data);
    }

    /**
     * 失败返回数据和消息
     *
     * @param apiCode 状态码
     * @param data    带返回数据
     * @return ApiResponse
     */
    protected ApiResponse failed(BaseApiCode apiCode, Object data) {
        return new ApiResponse(apiCode, apiCode.getCodeMsg(), data);
    }
}

ClaireConstant : 还没写什么内容

package com.claire.common;

/**
 * @author Claire
 * 常量类
 */
public class ClaireConstant {
}

 

 

StoriesMapper
package com.claire.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.claire.bean.Stories;

/**
 * @author Claire
 */
public interface StoriesMapper extends BaseMapper<Stories> {
}

 

 

StoriesService
package com.claire.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.claire.bean.Stories;
import com.claire.mapper.StoriesMapper;
import com.claire.utils.DataUtils;
import org.springframework.stereotype.Service;

/**
 * @author Claire
 */
@Service
public class StoriesService extends ServiceImpl<StoriesMapper, Stories> {

    public IPage<Stories> getTestStories(Long current,Long size){
        return baseMapper.selectPage(new Page<>(current,size),null);
    }

    public IPage<Stories> getStories(Long current,Long size,Stories sto){
        QueryWrapper<Stories> queryWrapper=new QueryWrapper<>();
        //分页条件
        queryWrapper.like(DataUtils.isNotEmptyStr(sto.getSTitle()),"s_title",sto.getSTitle());
        queryWrapper.like(DataUtils.isNotEmptyStr(sto.getSAuthor()),"s_author",sto.getSAuthor());
        queryWrapper.orderByDesc("create_time");
        return baseMapper.selectPage(new Page<>(current,size),queryWrapper);
    }
}

 

StoriesController
package com.claire.controller;

import com.claire.bean.Stories;
import com.claire.common.ApiResponse;
import com.claire.common.BaseController;
import com.claire.service.StoriesService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author Claire
 */
@RestController
@RequestMapping("/stories")
public class StoriesController extends BaseController {

    @Autowired
    private StoriesService storiesService;

    /**
     * 获取所有的故事
     * @param current
     * @param size
     * @param stories
     * @return
     */
    @RequestMapping(value = "/getStories",method = RequestMethod.POST,produces = "application/json;charset=UTF-8")
    public ApiResponse getStories(Long current, Long size, @RequestBody Stories stories){
        return success(storiesService.getStories(current,size,stories));
    }

    @RequestMapping("/testGetStories")
    public ApiResponse testGetStories(@RequestParam Long current,@RequestParam Long size){
        return success(storiesService.getTestStories(current,size));
    }

}

到这里,运行,就可以看到

 

当然期间可能会出现很多的错误,可以去咨询下几乎万能的百度。

那么接下来我们来建立前端的框架,然后尝试把Springboot与Vue整合在一起

 

搭建Vue框架

①装node.js  (自行百度)

②安装vue脚手架  (自行百度)

③创建Vue项目 

vue init webpack (项目名称)

  然后回车回车,安装路由(instal vue-router)那里选择y,其余的是否开启ESLint语法检测什么的就选n,一路往下就可以了

④运行这个项目

用VSCode打开它,Ctrl + ~打开终端,输入 npm install,装了淘宝镜像的可以选择 cnpm install 快一点

完成之后输入

npm run dev

,可以看到已经运行成功了,

去这网址就可以看到

 

Vue框架引入axios

引入这个是为了连接后台。

①安装axios

停止运行,回到终端,输入

cnpm(npm) install axios --save-dev

说一下后面这个-dev的作用

安装使用--save-dev简写为-D 的插件是被写入到 devDependencies 对象里面。

使用--save简写为-S 的插件是则被写入到 dependencies 对象里面

devDependencies  里面的插件只用于开发环境,不用于生产环境。

dependencies  则是需要发布到生产环境的。

②引入axios

在main.js中写入

import axios from "axios"


Vue.prototype.$http = axios;

axios.defaults.withCredentials = true

此时,main.js全貌:

接下来打开index.js

在proxyTable里面增加一些配置。本来后台的地址是8080,但是前端访问的地址也是8080,那么可以看到这里我写了8081(也可以写别的),因为端口会冲突,稍后会修改后台启动端口

proxyTable: {
      '/api': {
        target: 'http://localhost:8081', //后端请求服务域名和端口
        changeOrigin: true, //设置请求头
        pathRewrite: {
          '^/api': '' //路径重写
        }
      }
    },

 

Vue框架引入iView(可选)

这里我个人比较偏向于iView,当然也有很多人偏向于elementUI,都是可以的,不使用这个也是可以的。只是为了样式更方便写这个样子。

①安装

 npm install view-design --save

②引入

依然是main.js,写入

import ViewUI from "view-design";
import "view-design/dist/styles/iview.css";

Vue.use(ViewUI);

 

Springboot与Vue的通信

接下来测试一下,前台调用后台接口。

首先前端调用:

①assets是一个资源文件夹,删除里面的图片,创建三个文件夹css、img、js,在js里新增一个story.js

import Axios from "axios"
let prefix = "/api"

export default {

  /**
   * 测试获取所有的故事
   * @param {*} params 
   */
  getTestStories(params) {
    return new Promise((resolve, rejects) => {
      Axios.get(prefix + "/stories/testGetStories?current=" + params.current + "&&size=" + params.size)
        .then(response => {
          resolve(response.data);
        })
        .catch(error => {
          console.log("Error", error);
        })
    })
  }
}

 

修改HelloWorld.vue

<template>
  <div class="hello">
    <Button type="primary" @click="getTestStories">获取故事</Button>
  </div>
</template>

<script>
import StoryService from "../assets/js/story";
export default {
  name: "HelloWorld",
  data() {
    return {
      params: {
        current: 1,
        size: 3
      }, //获取故事的参数
      stories: [] //获取到的故事
    };
  },
  methods: {
    getTestStories() {
      StoryService.getTestStories(this.params).then(res => {
        if (res.code == 0) {
          this.stories = res.data.records;
          console.log(this.stories);
        } else {
          this.$Message.error(res.msg);
        }
      });
    }
  }
};
</script>


<style scoped>
</style>

同时删除App.vue 里的

Springboot整合Vue跨域解决

在config文件夹新增WebMvcConfig文件

package com.claire.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


/**
 * @author Claire
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * 跨域支持
     *
     * @return CorsFilter
     */
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        /* 是否允许请求带有验证信息 */
        corsConfiguration.setAllowCredentials(true);
        /* 允许访问的客户端域名 */
        corsConfiguration.addAllowedOrigin("*");
        /* 允许服务端访问的客户端请求头 */
        corsConfiguration.addAllowedHeader("*");
        /* 允许访问的方法名,GET POST等 */
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}

修改后台端口。在resources/application.yml里加入

启动项目,前后台都启动

打开localhost:8080

点击,可以看到在console打印台输出获取到的数据,修改一下HelloWorld.vue,用表格呈现

<template>
  <div class="hello">
    <Table stripe :columns="columns" :data="stories" style="width:1000px"></Table>
  </div>
</template>

<script>
import StoryService from "../assets/js/story";
export default {
  name: "HelloWorld",
  data() {
    return {
      params: {
        current: 1,
        size: 3
      }, //获取故事的参数
      stories: [], //获取到的故事
      columns: [
        {
          title: "id",
          key: "sid"
        },
        {
          title: "故事名称",
          key: "stitle"
        },
        {
          title: "故事作者",
          key: "sauthor"
        },
        {
          title: "故事内容",
          key: "content"
        },
        {
          title: "创建时间",
          key: "createTime"
        }
      ]
    };
  },
  methods: {
    getTestStories() {
      StoryService.getTestStories(this.params).then(res => {
        if (res.code == 0) {
          this.stories = res.data.records;
          console.log(this.stories);
        } else {
          this.$Message.error(res.msg);
        }
      });
    }
  },
  created() {
    this.getTestStories();
  }
};
</script>


<style scoped>
</style>

最后呈现效果:

 

 

前端部分:

https://gitee.com/tangjinxia/union_front.git

后台部分:

https://gitee.com/tangjinxia/union.git

数据库:

链接:https://pan.baidu.com/s/1CeVU661NG8ylGZ1dCHfJ1w
提取码:ri0j 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值