刚学完SpringBoot的朋友们都想要快速上手一个小项目,这里呢提供了一个看完就能自己写小项目的文章。会根据新手对于一个项目的搭建遇到的问题进行讲解,通过解决问题的方式去说明项目的搭建,而不是从项目本身下手,希望能够为大家解决入门的小问题。
首先文章遇到的技术栈主要是SpringBoot和Vue,会使用到Mybatis-plus,element-ui,echarts,后面提到的技术不需要懂也能看懂文章,这是一个前后端分离项目的搭建讲解,前端只需要懂一点点Vue语法,后续都会有详细介绍。
参考的视频是来自B站Up主“楠哥教你学java”,大家也可以去B站看他的视频,笔者也在学习阶段,懒得自己重新写一个项目了,后续再分享自己写的项目源码。
项目的构建流程就是,前端的搭建、后端的搭建、前后端的数据传递,补充echarts的使用(感觉挺好用的,就补充以下,不需要可以不看)。
前端的搭建用的是Vue-cli脚手架,然后代码复制的element-ui的组件,后续用的图表来自echarts,网站如下
https://element.eleme.cn/#/zh-CN/component/installation
https://echarts.apache.org/zh/index.html
新手一般遇到的问题有如下:
http://nodejs.cn/download/
查看版本号:
node -v
nmp -v
npm install cnpm -g
cnpm install vue-cli -g
npm install -g @vue/cli
vue ui
根据需求安装,比较傻瓜式
【Vue2】label、router、vuex选中即可
element-ui、axios、Echarts
import Vue from 'vue'
import './plugins/axios'
import App from './App.vue'
import router from './router'
import store from './store'
import './plugins/element.js'
import echarts from 'echarts'
Vue.prototype.$echarts = echarts
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
怎么复制使用,我们可以先来分析目录文件的组成。
整个项目,我们只用看src里面的文件
index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
配置固定,增加新的子页面时,需要import导入和增加属性
import Home from '../views/Home.vue'
{
path: '/',
name: 'Home',
component: Home
},
使用标签
柱状图
在views文件下创建一个Echarts.xue页面,先不用写代码,先到routers中进行路由注册
import Vue from 'vue'
import VueRouter from 'vue-router'
import Echarts from "../views/Echarts";
Vue.use(VueRouter)
const routes = [
{
path: '/Echarts',
name: 'Echarts',
component: Echarts
}
]
然后到App.Vue父页面中,增加路由跳转标签
选项栏
图表展示
注意:新手常犯,template是用来写视图层代码,该标签下只能有一个根目录,即 官网使用教程: https://echarts.apache.org/handbook/zh/get-started/ 到Echarts官网去copy一个组件的代码。 a.在script的export default中增加一个属性mounted(){}、并导入’echarts’包(在属性之外导入) b.在template中增加一个div展示容器 复制代码,将 关键代码如下,只用关注这些即可 通过对Echarts的解读我们可以知道,Echarts组件的使用是通过在mounted()属性中建立渲染视图,然后在template中绑定对应的属性进行展示,而element-ui更加符合Vue的生态,提供组件是整体的Vue代码。 element-ui组件:https://element.eleme.cn/#/zh-CN/component/table 同样的: 表格的标签简单解读下 算了不解读了,直接看就行,复制过来都看不懂的请自己去补一下html和vue语法。 从上面我们知道搭建一个子页面基本步骤为 其余页面我们还要一个增加数据的页面,和修改数据的页面,为了提高大家的举一反三能力,就不作解释了。前端页面建立好,不需要急着修改,如何与后端进行交互,等我们建立后端之后再来解读。 相信能看到这篇文章的同学,已经对如何创建SpringBoot项目已经很熟悉了。但是其实大多数人都只是用过Mabatis,没有用过Mybatis-Plus。其实Mybatis-Plus的作用就是实现一个自动化配置,它会帮你自动生成mapper配置文件、Dao、service。后端搭建的流程主要是:连接数据库-编写各个层级(Entity、DAO、Service、Controller)-各个层级的具体实现。 用了这个你会发现,什么Mybatis逆向工程都是lj。 在创建springboot工程的时候,选中lombok、springweb、sql driver。然后再导入以下依赖: ① 在java-com.xxx文件夹根目录下建立一个代码生成类 ② 运行一下,应有尽有 刚才是配置连接数据库生成文件,但是springboot项目的运行,还没有配置连接,即配置数据源。所以要在配置文件中配置,这里的配置文件格式用的是yml格式。 除此之外,因为自动生成的mapper文件在java目录下,所以还得手动加上MapperScan 自动生成完毕,配置也完成。我们只需要编辑一下Controller,返回表单所有值即可,然后到浏览器测试一下即可。 这里再说明一下RestController与Controller的区别 测试成功! 各个层级具体实现,其实在一些基础的CRUD操作中,Mabatis-Plus自动生成类中的方法已经够用,我们只需要写Controller即可。具体实现,我们将在第三部分展开,因为我们是依照前端需求去写我们的后端代码。现在前端需要对数据进行增删改查,并能用表单和图表的方式展现。 我们只需要解决以下两个问题即可实现前端与后端互连。 我们需要在接收的Vue页面script中,调用axios去get后台数据放入response对象中 这个时候我们运行前端,发现控制台的数据显示错误: 这是为什么呢,因为刚才的代码,只在前端去接收’http://localhost:8081/powerhuman/list’的数据,但是后端并没有发送数据,交流不一致。所以就有第二个问题: 加一个解决跨域问题的配置类即可 CorsRegistry:的全称为Cross-Origin Resource Sharing Registry ,直译过来就是跨域资源共享登记。是spring中解决跨域的一种方式 需要在配置类中引入@Configuration注解,SpringBoot才能识别到该配置文件,这个就涉及到boot的自动装配原理了, 然后实现 allowed后面跟的就是允许的相关事务 这样前后端的就实现了数据交流。 我们直接将tableData的数据清空,将tableData的数据换为response接收的data数据。这里做了一个this命名处理,因为在(response){}中this表示response这个对象,所以我们要用let使_this表示全局的this,这样才不会发生调用冲突。 前端代码分析: @click="handleDelete(scope.row)"这里对应绑定的是方法handleDelete,这个方法将返回这个区域的这一行的数据(scope.row),所以我们要在script中的method属性添加该方法: 同样的,前端数据若想传至后端,也需要使用axios去执行delete的Mapping操作,这里直接传入row.id即可,然后通过返回的值判断删除是否成功,成功则弹窗告知用户。要设置警告弹窗,可以到element-ui去找对应的组件进行配置。例如: 后端代码分析: 前端代码分析: 首先我们需要从编辑按钮跳转的编辑页面,这里补充Vue页面跳转方式: 1.声明式页内跳转 2.声明式页外跳转(新开页面)方式 注:router-link在页面渲染的时候是按照a标签的标准来的,即将router-link渲染成a标签 3.编程式页内跳转 4.编程式页外跳转(新开页面)方式 知识补充完毕后,我们来写这个跳转代码,通过handleEdit方法,同样提示弹窗,通过确定跳转。 需要一个表单页面,进行信息的接收和修改信息的传递。还记得一个前端页面建立步骤吗?就是在views中建立vue文件,然后到router中注册路径,因为这是修改表单,通过按钮直接跳转,所以不需要去使用router-link和router-view了。根据element-ui的表单组件,我们修改代码得如下 表单提交处理我们单独来看 后台代码分析: 增加操作和修改操作很相似,相比看了前面的案例,大家已经能举一反三弄出来,这里我就不作过多的解释了,然后增加操作推荐使用post方法进行数据交流。直接看代码: 前端 后端 综上所述,我们的CURD操作讲解就结束了,图表展示只是一个echarts的附加项,大家看完这里就可以去搞事请啦!搞懂知识点就自己从零搭建一个自己原创项目,搭建完你的收获即将满满! 这里补充一下数据校验的知识:原文链接:https://blog.csdn.net/qq_41402200/article/details/86016313 这里涉及的核心理念是:先找到前端页面的数据封装形式,因为前端和后端交互传递的是json数据,所以我们要在后端传递对应的数据格式到达前端,这里一般是建立一个类(类似entity),去进行return传递。 注意: 到此结束,原创不容易,望各位大佬一键三连!!!② Echarts组件使用说明
import * as echarts from 'echarts';
放置在外面(如果没导入)
其实两者比较好理解,通常created使用的次数多,而mounted通常是在一些插件的使用或者组件的使用中进行操作,比如插件chart.js的使用: var ctx = document.getElementById(ID);通常会有这一步,而如果你写入组件中,你会发现在created中无法对chart进行一些初始化配置,一定要等这个html渲染完后才可以进行,那么mounted就是不二之选。下面看一个例子(用组件)。【3】element-ui组件解读
① 在Views下创建一个视图,我们选择解读CURD操作绑定的表格
② 绑定视图后,去routers下的index.js中绑定路由
③ 整个,复制粘贴代码
【搭建流程小结】
二、后端的搭建
1、数据库搭建
USE `database`;
CREATE TABLE IF NOT EXISTS `powerhuman`(
`id` INT(4) NOT null,
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`power` INT(10) NOT NULL DEFAULT 0 COMMENT '能力值',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO powerhuman VALUES (1,'路飞',999);
INSERT INTO powerhuman VALUES (2,'索隆',888);
INSERT INTO powerhuman VALUES (3,'山治',666);
INSERT INTO powerhuman VALUES (4,'乌索普',10000);
--自增:auto_increment
2、编写各个层级(Mybatis-Plus)
【1】依赖导入
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.2version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.3.2version>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocityartifactId>
<version>1.7version>
dependency>
【2】代码自动生成(mybatis-plus)
package com.plord.power;
import com.baomidou.mybatisplus.annotation.DbType;
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.rules.NamingStrategy;
public class Generate {
public static void main(String[] args) {
//创建generator对象
AutoGenerator autoGenerator = new AutoGenerator();
//数据源
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL);
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("123456");
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/database");//指定连接数据库
autoGenerator.setDataSource(dataSourceConfig);
//全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");
globalConfig.setAuthor("admin");
globalConfig.setOpen(false);//是否打开文件
globalConfig.setServiceName("%sService");//设置Service的命名
autoGenerator.setGlobalConfig(globalConfig);
//包信息
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.plord");//将类放到包下,以下是指定包名
packageConfig.setEntity("entity");
packageConfig.setMapper("mapper");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.impl");
packageConfig.setController("controller");
autoGenerator.setPackageInfo(packageConfig);
//策略配置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setInclude("powerhuman");//连接的表名,可多表同时执行,用逗号隔开即可
strategyConfig.setNaming(NamingStrategy.underline_to_camel);//下划线转驼峰
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
strategyConfig.setEntityLombokModel(true);//是否使用lombok插件生成entity文件
autoGenerator.setStrategy(strategyConfig);
//运行
autoGenerator.execute();
}
}
【3】配置文件
spring:
datasource:
url: jdbc:mysql://localhost:3306/database
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
#打印sql语句
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#指定扫描的mapper文件夹
mapper-locations: classpath:com/plord/mapper/xml/*.xml
server:
port: 8081
@MapperScan("com.xxx.mapper")
【4】测试
@RestController
@RequestMapping("//powerhuman")
public class PowerhumanController {
@Autowired
private PowerhumanService service;
@RequestMapping("/list")
public List<Powerhuman> test(){
return service.list();
}
}
3、各个层级的具体实现
三、前后端数据传递
【1】搭建前端和后台的联系
① 前端如何连接后台?
created() {
axios.get('http://localhost:8081/powerhuman/list').then(function (response) {
console.log(response)
})
},
② 后端如何连接前端
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 CrosConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
WebMvcConfigurer
接口中的 addCorsMappings
方法【2】CRUD前端可视化实现
① 将数据转换为表格
② 删除操作
methods: {
handleDelete(row){
axios.delete('http://localhost:8081/powerhuman/delete/'+row.id).then(function (response) {
if(response.data){
alert("删除成功")
}
})
}
}
methods: {
handleDelete(row){
this.$confirm('此操作将永久删除'+row.name, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.delete('http://localhost:8081/powerhuman/delete/'+row.id).then(function (response) {
if(response.data){
alert("删除成功")
}
})
location.reload()//自动刷新
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
@DeleteMapping("/delete/{id}")
public boolean deleteById(@PathVariable("id") Integer id){
return service.removeById(id);
}
③ 更新操作
this.$router.push({ path: '/a' });
//带参数形式1
this.$router.push({ path: '/a', query: {'userid': 666, 'username': 'itachi'}});
//带参数形式2
this.$router.push({ path: '/a?userid=666&username=itachi'});
window.open('#/a', '_blank');
//带参数方式
window.open('#/a?userid=' + userid + '&username' + username, '_blank');//这里一定要注意路径
handleEdit(row){
this.$confirm('此操作将进入'+row.name+'的修改页面', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$router.push('/edit')
}).catch(() => {
this.$message({
type: 'info',
message: '已取消修改'
});
});
}
methods: {
onSubmit() {
let _this = this
axios.put("http://localhost:8081/powerhuman/update",this.form).then(function (response) {
if(response.data){
_this.$alert("修改成功")
_this.$router.push('/table')
}
else {
_this.$alert("修改失败")
_this.$router.push('/table')
}
})
},
noSubmit(){
this.$router.push('/table')
}
}
@PutMapping("update")
public boolean update(@RequestBody Powerhuman powerhuman){
return service.updateById(powerhuman);
}
④ 增加操作
@PostMapping("/insert")
public boolean add(@RequestBody Powerhuman powerhuman){
return service.save(powerhuman);
}
Rules: {
userName: [
{
required: true,
message: "请输入用户名称",
trigger: "blur"
}
]
}
【3】图表展示
① 建立传递的数据实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EchartsPieValue {
private Integer value;
private String name;
}
② Service层封装传递的数据
public class PowerhumanServiceImpl extends ServiceImpl<PowerhumanMapper, Powerhuman> implements PowerhumanService {
@Override
public List<EchartsPieValue> pieList() {
List<EchartsPieValue> pielist = new ArrayList<>();
List<Powerhuman> powerhumanList = getBaseMapper().selectList(null);
for(Powerhuman powerhuman:powerhumanList){
EchartsPieValue value = new EchartsPieValue();
value.setName(powerhuman.getName());
value.setValue(powerhuman.getPower());
pielist.add(value);
}
return pielist;
}
}
③ Controller层传递数据
@GetMapping("/pievalue")
public List<EchartsPieValue> pieValueList(){
return service.pieList();
}
④ 前端代码