Vue+springboot的简单项目搭建

90 阅读2分钟

前端vue

先执行vue init webpack vue-new
​
cd vue-new
# 安装路由
cnpm insatll vue-router --save-dev
# 安装element-ui
cnpm i element-ui -S
# 安装依赖
cnpm install
# 安装SASS加载器
cnpm insall sass-loader node-sass --save-dve
# 启动测试
npm run dev

main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import axios from 'axios'
import router from './router'//路由
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
Vue.config.productionTip = falseimport moment from 'moment'
Vue.prototype.$moment = moment
​
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'Vue.use(router);
Vue.use(ElementUI);
​
/* eslint-disable no-new */
new Vue({
  el: '#app',
  // components: { App },
  // template: '<App/>'
  router,
  render:h=>h(App)
})

Login.vue

<template>
  <div>
    <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
      <h3 class="login-title">欢迎登录</h3>
      <el-form-item lable="账号" prop="username">
        <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
      </el-form-item>
      <el-form-item lable="密码" prop="password">
        <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" v-on:click="onsubmit('loginForm')">登录</el-button>
      </el-form-item>
    </el-form>
​
    <el-dialog
      title="温馨提示"
      :visible.sync="dialogVisible"
      width="30%"
      :before-close="handleClose">
      <span>请输入账号和密码</span>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="dialogVisible = false">确定</el-button>
      </span>
    </el-dialog>
  </div>
</template><script>
export default {
  name: "Login",
  data(){
    return{
      form :{
        username:'',
        password:''
      },
      rules:{
        username:[
          {required:true,message:'账号不能为空',trigger:'blur'}
        ],
        password:[
          {required:true,message:'密码不能为空',trigger:'blur'}
        ]
      },
      dialogVisible:false
    }
  },
    
  methods:{
    onsubmit(loginForm){
      this.$refs[loginForm].validate((valid)=>{
        // console.log(this.form.username)
        // console.log(this.form.password)
        // console.log(loginForm)
        // console.log(valid)
        // 先进行数据校验,校验通过true才能传数据
        if (valid){
          this.axios.post('http://localhost:8083/user/login',
            {'username':this.form.username,'password':this.form.password}).then(
            (resp)=>{
              console.log(resp.data.code)
              if (resp.data.code===200){
                this.$router.push("/blog")
              }else {
                console.log(false)
                alert(resp.data.msg)
              }
            }
​
          )
        }else {
            //如果数据校验不通过就弹窗
          this.dialogVisible=true;
          return false;
        }
      })
​
      // this.axios.post('http://localhost:8083/user/login',
      //   {'username':this.form.username,'password':this.form.password}).then(
      //   (resp)=>{
      //     console.log(resp.data.code)
      //     if (resp.data.code===200){
      //       this.$router.push("/blog")
      //     }else {
      //       console.log(false)
      //     }
      //   }
      //   )
​
    }
  }
}
</script>
<style scoped>
.login-box{
  border: 1px solid #DCDFE6;
  width: 350px;
  margin: 180px auto;
  padding: 35px 35px 15px 15px;
  border-radius: 5px;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  box-shadow: 0 0 25px #909399;
}
.login-title{
  text-align: center;
  margin: 0 auto 40px auto;
  color: #303133;
}
</style>

Main.vue

<template>
  <el-container style="border: 1px solid #eee">
    <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
  <el-radio-group v-model="isCollapse" style="margin-bottom: 20px;">
    <el-radio-button :label="false">展开</el-radio-button>
    <el-radio-button :label="true">收起</el-radio-button>
  </el-radio-group>
  <el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" :collapse="isCollapse">
    <el-submenu index="1">
      <template slot="title">
        <i class="el-icon-location"></i>
        <span slot="title">导航一</span>
      </template>
      <el-menu-item-group>
<!--        <span slot="title">分组一</span>-->
        <el-menu-item index="1-1">
          <router-link to="/blog">博客页面</router-link>
        </el-menu-item>
        <el-menu-item index="1-2">
          <router-link to="/user/list">用户页面</router-link>
​
        </el-menu-item>
      </el-menu-item-group>
<!--      <el-menu-item-group title="分组2">-->
        <el-menu-item index="1-3">选项3</el-menu-item>
<!--      </el-menu-item-group>-->
      <el-submenu index="1-4">
        <span slot="title">选项4</span>
        <el-menu-item index="1-4-1">选项1</el-menu-item>
      </el-submenu>
    </el-submenu>
    <el-menu-item index="2">
      <i class="el-icon-menu"></i>
      <span slot="title">导航二</span>
    </el-menu-item>
    <el-menu-item index="3" disabled>
      <i class="el-icon-document"></i>
      <span slot="title">导航三</span>
    </el-menu-item>
    <el-menu-item index="4">
      <i class="el-icon-setting"></i>
      <span slot="title">导航四</span>
    </el-menu-item>
  </el-menu>
    </el-aside>
​
    <el-main>
      <router-view></router-view>
    </el-main>
  </el-container>
</template><script>
export default {
  name: "Main",
  data() {
    return {
      isCollapse: true
    };
  },
  methods: {
    handleOpen(key, keyPath) {
      console.log(key, keyPath);
    },
    handleClose(key, keyPath) {
      console.log(key, keyPath);
    }
  }
}
​
</script><style scoped>
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 200px;
  min-height: 400px;
}
</style>

Blog.vue

<!--<template>-->
<!--  <div>-->
<!--    <table>-->
<!--      <tr>-->
<!--        <td>编号</td>-->
<!--        <td>作者id</td>-->
<!--        <td>题目</td>-->
<!--        <td>描述</td>-->
<!--        <td>文章</td>-->
<!--        <td>创建时间</td>-->
<!--        <td>状态</td>-->
<!--      </tr>-->
<!--      <tr v-for="item in books">-->
<!--        <td>{{item.id}}</td>-->
<!--        <td>{{item.userId}}</td>-->
<!--        <td>{{item.title}}</td>-->
<!--        <td>{{item.description}}</td>-->
<!--        <td>{{item.content}}</td>-->
<!--        <td>{{item.created}}</td>-->
<!--        <td>{{item.status}}</td>-->
<!--      </tr>-->
<!--    </table>-->
<!--  </div>-->
<!--</template>--><template>
  <el-table
            <!--data赋值 -->
    :data="books"
    style="width: 100%">
​
    <el-table-column
      label="编号"
      width="180">
      <template slot-scope="scope">
           <!-- 插槽 -->
        <el-popover trigger="hover" placement="top">
          <p>id:{{scope.row.id}}</p>
          <div slot="reference" class="name-wrapper">
            <el-tag size="medium">{{scope.row.id}}</el-tag>
          </div>
        </el-popover>
      </template>
    </el-table-column>
​
      <el-table-column
        label="作者id"
        width="180">
        <template slot-scope="scope">
          <el-popover trigger="hover" placement="top">
            <p>作者Id:{{scope.row.userId}}</p>
            <div slot="reference" class="name-wrapper">
              <el-tag size="medium">{{scope.row.userId}}</el-tag>
            </div>
          </el-popover>
        </template>
      </el-table-column>
​
      <el-table-column
        label="题目"
        width="180">
        <template slot-scope="scope">
          <el-popover trigger="hover" placement="top">
            <p>题目:{{scope.row.title}}</p>
            <div slot="reference" class="name-wrapper">
              <el-tag size="medium">{{scope.row.title}}</el-tag>
            </div>
          </el-popover>
        </template>
      </el-table-column>
​
​
      <el-table-column
        label="描述"
        width="180">
        <template slot-scope="scope">
          <el-popover trigger="hover" placement="top">
            <p>描述:{{scope.row.description}}</p>
            <p>文章:{{scope.row.content}}</p>
            <div slot="reference" class="name-wrapper">
              <el-tag size="medium">{{scope.row.description}}</el-tag>
            </div>
          </el-popover>
        </template>
      </el-table-column>
​
    <el-table-column
      label="创建日期"
      width="180">
      <template slot-scope="scope">
        <!--        插槽-->
        <i class="el-icon-time"></i>
        <span style="margin-left: 10px">{{$moment(scope.row.created).format('YYYY-MM-DD')  }}</span>
      </template>
    </el-table-column>
​
    <el-table-column label="操作">
      
      <template slot-scope="scope">
        <el-button
          size="mini"
          @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
        <el-button
          size="mini"
          type="danger"
          @click="handleDelete(scope.$index, scope.row)">删除</el-button>
      </template>
    </el-table-column>
​
​
​
  </el-table>
</template><script>
export default {
  name: "book",
  data(){
    return{
      books:[
      ]
    }
  },
  created(){
    const _this = this;
      //用axios来请求
    this.axios.get('http://localhost:8083/blog/findAll').then(
      function(resp){
        console.log(resp);//放回回来的resp
        _this.books = resp.data;//赋值
      }
    )
  }
}
</script><style scoped></style>

router/index.js

//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Blog from "../views/Blog";
import Login from "../views/Login";
import Main from "../views/Main";
import User from "../views/user/User"
//使用
Vue.use(VueRouter);
//导出
export default new VueRouter({
  mode: 'history',
//   scrollBehavior (to, from, savedPosition) { //解决跳转下一个页面底部的方法
//   if (savedPosition) {
//     return savedPosition
//   } else {
//     return { x: 0, y: 0 }
//   }
// },
  routes: [
    //首页
    {
      path: '/',
      component: Login
    },
    {
      path: '/main',
      component: Main,
      children:[//路由嵌套
        {path:'/blog', name:'blog', component:Blog,props:true},
        {path:'/user/list', name:'userList', component:User,props:true},
      ]
    },
  ]
​
​
})

导入依赖

<dependencies>
​
    <!-- 数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- mybatis-plus -->
    <!-- mybatis-plus 是自己开发,并非官方的! -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.0</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </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><build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

运行

package com.ycz;/*
 @author ycz
 @date 2021-09-08-19:14
*/
​
​
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
​
import java.util.ArrayList;
​
/**
 * 代码自动生成器
 */
public class Test2 {
    public static void main(String[] args) {
        AutoGenerator mpg=new AutoGenerator();
        //全局配置
        GlobalConfig config=new GlobalConfig();
        config.setAuthor("ycz");
        String projectPath = System.getProperty("user.dir");
        config.setOutputDir(projectPath+"/src/main/java");
        config.setOpen(false);//是否自动打开文件夹
        config.setFileOverride(false);//是否覆盖
        config.setIdType(IdType.ID_WORKER);
        config.setServiceName("%sService"); // 去Service的I前缀
        config.setDateType(DateType.ONLY_DATE);
        config.setSwagger2(true);
        mpg.setGlobalConfig(config);
​
        DataSourceConfig dataSourceConfig=new DataSourceConfig();
        dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/vueblog?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("123456");
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSourceConfig.setDbType(DbType.MYSQL);
        mpg.setDataSource(dataSourceConfig);
​
        PackageConfig pc = new PackageConfig();
     //  pc.setModuleName("blog");
        pc.setParent("com.ycz");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);
​
​
        StrategyConfig strategy=new StrategyConfig();
        strategy.setInclude("m_user");// 设置要映射的表名
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true); // 自动lombok;
        strategy.setLogicDeleteFieldName("deleted");
​
        TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
        TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        strategy.setTableFillList(tableFills);
        // 乐观锁
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true); //localhost:8080/hello_id_2
        mpg.setStrategy(strategy);
        mpg.execute(); //执行
​
​
​
    }
​
​
}

配置config

package com.ycz.config;/*
 @author ycz
 @date 2021-10-10-13:57
*/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 MyConfig implements WebMvcConfigurer {
    //重新addCorsMappings方法
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")      //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置
                .allowedOriginPatterns("*")            //开放哪些ip、端口、域名的访问权限
                .allowedMethods( "GET", "POST", "PUT", "OPTIONS", "DELETE")        //开放哪些Http方法,允许跨域访问
                .allowCredentials(true)         //是否允许发送Cookie信息
                .maxAge(3600)
                .allowedHeaders("*");            //允许HTTP请求中的携带哪些Header信息
    }
​
}

UserController

package com.ycz.controller;
​
​
import com.ycz.entity.MUser;
import com.ycz.service.MUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
​
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
​
/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author ycz
 * @since 2021-10-10
 */
@RestController
@RequestMapping("/user")
public class MUserController {
    @Autowired
    private MUserService userService;
    @PostMapping("/login")
    public Map<String,Object> login(@RequestBody MUser user){
        System.out.println(user);
​
        Map<String,Object> map1=new HashMap<>();
        map1.put("username",user.getUsername());
        map1.put("password",user.getPassword());
        Collection<MUser> mUsers = userService.listByMap(map1);
​
        System.out.println(mUsers);
        Map<String,Object> maps=new HashMap<>();
        if (mUsers.isEmpty()){
            maps.put("msg","操作失败");
            maps.put("code",500);
        }else {
            maps.put("msg","操作成功");
            maps.put("code",200);
        }
        return maps;
    }
​
​
    @GetMapping("/list")
    public List<MUser> getList(){
        return userService.list(null);
    }
​
}

BlogController

package com.ycz.controller;
​
​
import com.ycz.entity.MBlog;
import com.ycz.service.MBlogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
​
import org.springframework.web.bind.annotation.RestController;
​
import java.util.List;
​
/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author ycz
 * @since 2021-10-10
 */
@RestController
@RequestMapping("/blog")
public class MBlogController {
​
    @Autowired
    private MBlogService blogService;
​
    @GetMapping("/findAll")
    public List<MBlog> blogList(){
        return blogService.list(null);
    }
​
}

\