springboot+Vue项目-微博留言(前后端分离,跨域)

所用技术

  • 数据库:mysql
  • 后台框架:springboot,mybatis plus
  • 前台框架:Vue
  • 实体类:lombok
  • 异步:axios

一丶微博留言后端

小贴士:约定>配置>编码
先做好准备,在去写代码

1.sql语句

CREATE TABLE `ol_msg` (
  `id` VARCHAR(200)  PRIMARY KEY ,
  `create_date` DATETIME DEFAULT NULL,
  `content` VARCHAR(2000) DEFAULT NULL,
  `acc` INT(8) DEFAULT NULL,
  `ref` INT(8) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8

2.改pom

<?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>
    <groupId>com.chufeng</groupId>
    <artifactId>springboot-vue-blog</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-vue-blog</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.4.1</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <fork>true</fork>
                        <addResources>true</addResources>
                    </configuration>
                </plugin>


            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <mainClass>com.chufeng.springbootvueblog.SpringbootVueBlogApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>


3.写yml文件

server:
    port: 8080

spring:
    application:
        name: springboot-vueblog
    datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        name: defaultDataSource
        password: 123456
        url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
        username: root

4.业务类

BlogMapper

package com.chufeng.springbootvueblog;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chufeng.springbootvueblog.entities.Blog;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BlogMapper extends BaseMapper<Blog> {
}

BlogService接口

package com.chufeng.springbootvueblog.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.chufeng.springbootvueblog.entities.Blog;

public interface BlogService extends IService<Blog> {
}

BlogServiceImpl实现类

package com.chufeng.springbootvueblog.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chufeng.springbootvueblog.entities.Blog;
import com.chufeng.springbootvueblog.mapper.BlogMapper;
import com.chufeng.springbootvueblog.service.BlogService;

public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements BlogService {
}

5.配置类
MybatisPlusConfig 数据分页配置类

package com.chufeng.springbootvueblog.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
@Configuration
public class   MyBatisPlusConfig {
    // 最新版分页
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

AppConfig跨域配置类

package com.chufeng.springbootvueblog.config;

import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class AppConfig {
    // 全局跨域配置: 可以在java后台配置,也可以在vue前台配置
    private CorsConfiguration addCorsConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //请求常用的三种配置,*代表允许所有,当时你也可以自定义属性(比如header只能带什么,只能是post方式等等)
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", addCorsConfig());
        return new CorsFilter(source);
    }
}

BlogController

package com.chufeng.springbootvueblog.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chufeng.springbootvueblog.entities.Blog;
import com.chufeng.springbootvueblog.service.BlogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@Slf4j
@RestController
@RequestMapping("/api/blogs")
public class BlogController {

    @Resource
    private BlogService blogService;

    @GetMapping
    public IPage<Blog> selectByPage(Integer pageNo, Integer pageSize){
        return blogService.page(new Page<>(pageNo,pageSize));
    }
    @PostMapping
    public boolean savaBlog(@RequestBody Blog blog){
        //打印日志
        log.info(blog.toString());
        return blogService.save(blog);
    }
    @DeleteMapping("/{id}")
    public boolean deleteBlogById(@PathVariable("id") String id ){
        return blogService.removeById(id);
    }
    @PutMapping
    public boolean updateBlog(@RequestBody Blog blog){
        return blogService.updateById(blog);
    }
}

二丶Vue前端

需要导入

  • bootstrap.css
  • axios.js
  • jquery.js
  • vue.js

自定义css代码

@charset "utf-8";

*{margin:0; padding:0;}
li{list-style:none;}
img{border:none;}
a{text-decoration:none;}
input,textarea{outline:none; resize:none; border:none;}
.clearfix:after{visibility:hidden;display:block;font-size:0;content:" ";clear:both;height:0;}
.clearfix{*zoom:1;}

body{background:url(../img/bg.jpg) center center no-repeat; background-size:100% 140%;}
/*登陆*/
.loginBox{
	width:278px; padding:30px 80px 20px 80px; margin:40px auto; 
	background-image: -webkit-linear-gradient(top,rgb(255,255,255),rgb(242,242,242));
	box-shadow: 0 0 3px rgba(21,62,78,0.8); position:relative;
	border-radius:2px;
}
.loginList{width:100%;}
.loginList li{margin-bottom:10px; overflow:hidden;}
.hTxt{font:18px/1.5 "Microsoft YaHei";}
.inputs{width:260px; display:block; font-weight:bold; background:url(../img/inputBg.png) 0 0 no-repeat; height:14px; line-height:14px; padding:9px; color:#666;}
.loginList .btns{text-align:right; background:none; width:280px;}
.reg{background:url(../img/btns.png) 0 -42px no-repeat; width:70px; height:42px; display:inline-block; overflow:hidden; opacity:.8;}
.login{background:url(../img/btns.png) 0 0 no-repeat; width:70px; height:42px; display:inline-block; overflow:hidden; opacity:.8;}
.reg:hover,.login:hover{opacity:1;}
.reg:active,.login:active{opacity:.9;}
.look{text-align:right; font:12px/1.2 "Microsoft YaHei"; color:#999;}

/*ad*/
.ad{background:url(../img/ad.png) left top no-repeat; position:fixed; bottom:20px; height:16px; left:50%; width:106px; margin-left:-53px;}
::selection {background-color:#669900; color:#ffffff;}
::-moz-selection {background-color:#669900; color:#ffffff;}

weibo.css代码

@charset "utf-8";body,ul,ol,li,dl,dt,dd,p,h1,h2,h3,h4,h5,h6,form,fieldset,table,td,img,div{margin:0;padding:0;border:0}
body{font-size:12px;font-family:"Microsoft YaHei"}
ul,ol{list-style-type:none}
select,input,img,select{vertical-align:middle}
a{text-decoration:underline;color:#313030}
a{blr:expression(this.onFocus=this.blur())}
input,textarea{outline:0;resize:none}
a{outline:0}
.msgArea{width:755px;overflow:hidden;margin:0 auto;font-family:"Microsoft YaHei"}
.commentOn{width:753px;display:block;overflow:hidden;border:#a5bcff solid 1px;background:#f3f8fd;margin-top:25px;font-family:Verdana}
.reply{overflow:hidden;padding:10px 20px;background:#FFF;border-top:#e9e9e9 solid 1px;border-bottom:#e9e9e9 solid 1px}
.userInfo{display:block;overflow:hidden;height:25px;border-bottom:#bababa solid 1px}
.userName{float:left;background:url(../img/userBj.png) left center no-repeat;padding-left:15px;color:#000;font-size:14px;font-weight:bold}
.replyTime{float:left;color:#8b8585;line-height:30px;font-size:11px}
.replyContent{line-height:24px;font-size:14px;color:#2b2b2b;font-family:"Microsoft YaHei"}
.operation{clear:both;width:100%;height:30px;margin-top:8px}
.handle{float:right;padding-top:6px}
.handle a{text-decoration:none;float:left;margin-left:12px;background:url(../img/icons.png) 0 0 no-repeat;height:18px;line-height:18px;padding-left:20px}
.handle .top_icon{background-position:0 0}
.handle .down_icon{background-position:0 -17px}
.handle .cut{background-position:0 -33px}
.handle a:active{color:#09F}
.noContent{text-align:center;display:block;background:#FFF;font:14px/2.3 "Microsoft YaHei";border-bottom:#e9e9e9 solid 1px;border-top:#e9e9e9 solid 1px;color:#999}
.takeComment{width:713px;display:block;overflow:hidden;border:#a5bcff solid 1px;background:#f3f8fd;margin-top:25px;font-family:Verdana;padding:15px 20px}
.takeTextField{width:701px;height:70px;border:#b1b1b1 solid 1px;clear:both;display:block;margin:10px 0 10px 0;line-height:20px;padding:5px;box-shadow:inset 0 0 5px #DDD;font-family:"Microsoft YaHei"}
.takeSbmComment{display:block;overflow:hidden}
.takeSbmComment span{float:right;color:#CCC;line-height:37px;padding-right:10px}
.inputs{float:right;width:125px;height:37px;border:none 0;background:tranparent;background:url(../img/takeSbmComment.png) left top no-repeat;cursor:pointer;opacity:.8}
.inputs:hover{opacity:1}
.inputs:active{opacity:.9}
.messList{overflow:hidden}
.page{text-align:right;font-size:0;font-family:Verdana;padding:10px 16px}
.page a{display:inline-block;height:20px;padding:0 7px;border:#CCC solid 1px;font:12px/20px Verdana;text-decoration:none;margin-left:5px;background:#FFF}
.page a:hover{background:#09F;color:#FFF;border-color:#09F}
.page .active{background:#CCC}
.page a:active{opacity:.8}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <!--公共样式-->
  <link href="css/common.css" rel="stylesheet" />
  <!--微博样式-->
  <link href="css/weibo.css" rel="stylesheet" />
  <!--bootstrap-->
  <link href="css/bootstrap.css" rel="stylesheet" />
  <script src="js/vue.js"></script>
  <script src="js/axios.js"></script>
  <title>微博</title>
</head>
<body>
<div id="app" class="container">
    <!--留言-->
    <div class="takeComment">
        <!--回复内容-->
        <textarea name="textarea" class="takeTextField" id="tijiaoText" v-model="content" v-on:keyup.enter="addBlog()"></textarea>
        <div class="takeSbmComment">
            <!--回复按钮-->
            <button class="btn btn-default" @click.stop="addBlog()">回复</button>
            <span>(可按 Enter 回复)</span>
        </div>
    </div>
    <!--已留-->
    <div class="commentOn">
        <!--如果没有数据,显示暂无留言-->
        <div class="noContent">暂无留言</div>
        <!--如果查询有数据,使用列表显示-->
        <div class="messList">

            <div class="reply" v-for="(item,index) in records">
                <p class="replyContent" v-cloak>{{item.content}}</p>
                <p class="operation">
                    <span class="replyTime" v-cloak>{{item.createDate}}</span>
                    <span class="handle">
                                {{userid}}{{useracc}}{{userref}}
								<button class="top" @click="updateAcc(item)">{{item.acc}}</button>
								<button class="down_icon"@click="updateRef(item)" >{{item.ref}}</button>
								<button @click="delMsg(item.id)">删除</button>
							</span>
                </p>
            </div>

        </div>
        <p>
            总数据:{{total}}
            <a>下一页</a>
        </p>
    </div>
</div>
<script>
    //创建一个axios的实例
    let http=axios.create(({//基础配置
        baseURL: 'http://127.0.0.1:8081/api/',
        timeout:1000
    }))
    let _this;
    let  vm=new Vue({
       el:"#app",
        data:{
            content:'',//添加评论的内容
            records:[],//数组数组
            pageNo:1,//默认页码
            pageSize:2,//默认页大小
            total:0,//总数据,
            userid:1,
            useracc:0,
            userref:0
        },
        mounted(){//挂载
           _this=this;
           this.initData(this.pageNo,this.pageSize);
        },
        methods:{
           initData:function (pageNo,pageSize){

               http.get("/blogs?pageNo="+pageNo+"&pageSize="+pageSize+"")
               .then(function (resp){
                   //注意取值的时候要使用resp.data
                   _this.records=resp.data.records;
                   _this.total=resp.data.total;
                   console.log("相应数据"+resp);
               })//成功回调
               .catch(function (error){
                   console.log(error)
               })
           },
            addBlog:function (){
               let data={
                   "content":this.content,
                   "acc":10,
                   "ref":0
               }
               http.post("/blogs",data)
                .then(function (resp){
                    console.log(resp);

                    //清空内容
                    _this.content="";
                    _this.initData(_this.pageNo,_this.pageSize);
                }).catch(function (error){
                    console.log(error)
               })
            },// 删除
            delMsg:function(id){
                http.delete("/blogs/"+id)
                    .then(function(resp){
                        console.log(resp);

                        // 重新加载数据
                        _this.initData(_this.pageNo,_this.pageSize);
                    })
                    .catch(function(error){
                        console.log(error)
                    })
            },//修改
            updateAcc:function(data) {

                data.acc=data.acc+1;
                console.log(data)
                http.put("/blogs",data)
                    .then(function (resp) {
                        console.log(resp);
                        // 重新加载数据
                        _this.initData(_this.pageNo,_this.pageSize);
                    })
                    .catch(function (error) {
                        console.log(error)
                    })
            },
            updateRef:function(data) {

                data.ref=data.ref+1;
                console.log(data)
                http.put("/blogs",data)
                    .then(function (resp) {
                        console.log(resp);
                        // 重新加载数据
                        _this.initData(_this.pageNo,_this.pageSize);
                    })
                    .catch(function (error) {
                        console.log(error)
                    })
            }
        }

    });
</script>
</body>
</html>

最终效果
在这里插入图片描述

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值