项目练习01

1.项目介绍

这是一个简单的项目练习,用于掌握新学习的SpringBoot技术。

  • 项目操作界面

● 技术栈

Vue3+ElementPlus+Axios+MyBatisPlus+SpringBoot 前后端分离

前后端分离开发,前端主体框架 Vue3 + 后端基础框架 SpringBoot

  1. 前端技术栈:Vue3+Axios+ElementPlus
  2. 后端技术栈:Spring Boot + MyBatisPlus
  3. 数据库-MySQL
  4. 项目的依赖管理-Maven
  5. 分页-MyBatis Plus 的分页插件

2.功能01-搭建Vue前端工程

2.1代码实现

以下过程,前面在讲解SSM_VUE项目时已经安装过了,包括整个vue项目的创建过程、项目结构,具体看SSM整合day02的功能01实现的笔记

  1. 先下载node.js LTS 并安装node.js的npm,用于管理前端项目包依赖

  2. 创建Vue项目(需要联网)

    1)创建项目,指令vue create <项目名>

    2)选择 Manually select features

    3)用空格键选择Bebel、Router、Vuex

    4)选择3.x

    5)Use history mode for router? 输入Y,回车

    6)Where do you prefer placing config for Babel, ESLint, etc.? 选择In package. json

    7)Save this as a preset for future projects? (y/N) 是否要保存当前的设置,根据你意思随意选择,如果选择了的话会有 Save preset as: 让你命名当前保存的设置

    8)最后回车

    9)创建完毕的显示结果如下

  3. 使用idea打开刚创建的vue项目,并配置项目启动

    1)点击配置Configuration,配置npm方式启动项目

    2)选择serve,其他保持默认,保存

    3)点击运行,即可在提示的地址访问项目

  4. 停止项目,安装element-plus插件,在项目中运行指令npm install element-plus --save

  5. 在vue.config.js中修改项目的端口,防止端口占用

module.exports = {
devServer: {
port: 10000//启动端口
}
}

3.功能02-创建项目基础界面

这个功能步骤在ssm整合框架day01-功能02中也有详细描述,这里不再赘述

3.1需求分析

页面原型:

3.2思路分析

使用vue3+ElementPlus完成

3.3代码实现

(1)修改Home.vue,引入表单、搜索框、按钮组件

<template>
<div>
<div style="margin: 10px 0">
<el-button type="primary">新增</el-button>
<el-button>其它</el-button>
</div>
<!--搜索-->
<div style="margin: 10px 0">
<el-input v-model="search" placeholder=" 请 输 入 关 键 字 " style="width:30%"></el-input>
<el-button style="margin-left: 10px" type="primary">查询</el-button>
</div>
<el-table :data="tableData" stripe style="width: 100%">
<el-table-column sortable prop="date" label="日期"></el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column fixed="right" label="操作" width="100">
<template #default="scope">
<el-button @click="handleEdit(scope.row)" type="text">编辑</el-button>
<el-button type="text">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'HomeView',
components: {
},
data() {
return {
search : '',
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄',
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
}
]
}
},
methods: {
handleEdit() {
}
}
}
</script>

(2)删除HelloWorld.vue组件

(3)创建components/Header.vue

(4)创建全局的global.css(src/assets/css/global.css),以后有全局样式可以放在这里

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

(5)修改src/main.js,引入global.css,同时引入ElementPlus,顺便国际化

import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
//引入css
import '@/assets/css/global.css' //引入ElementPlus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
//国际化
import zhCn from 'element-plus/es/locale/lang/zh-cn' createApp(App).use(store).use(router).use(ElementPlus, {locale: zhCn}).mount('#app')

(6)Header.vue,引入ElementPlus组件的下拉框

<template>
<div style="height: 50px; line-height: 50px; border-bottom: 1px solid #ccc; display:flex">
<div style="width: 200px; padding-left: 30px;
font-weight: bold; color: dodgerblue">后台管理
</div>
<div style="flex: 1"></div>
<div style="width: 100px">
<el-dropdown>
<span class="el-dropdown-link" style="padding: 18px">
tom<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>个人信息</el-dropdown-item>
<el-dropdown-item>退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</template>
<script>
export default {
name: "Header"
}
</script>
<style scoped>
</style>

(7)创建侧边栏组件Aside.vue,引入导航菜单组件

<template>
<div>
<!--说明-先去掉这两个方法, 否则会报错-->
<!--@open="handleOpen"-->
<!--@close="handleClose"-->
<el-menu
style="width: 200px"
default-active="2"
class="el-menu-vertical-demo">
<el-sub-menu index="1-4">
<template #title>选项 4</template>
<el-menu-item index="1-4-1">选项 1</el-menu-item>
</el-sub-menu>
<el-menu-item index="2">
<i class="el-icon-menu"></i>
<template #title>导航二</template>
</el-menu-item>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<template #title>导航三</template>
</el-menu-item>
<el-menu-item index="4">
<i class="el-icon-setting"></i>
<template #title>导航四</template>
</el-menu-item>
</el-menu>
</div>
</template>
<script>
export default {
name: "Aside"
}
</script>
<style scoped>
</style>

(8)在App.vue将页面分成三部分

<template>
<div>
<!--头部-->
<Header/>
<!--主体-->
<div style="display: flex">
<!--侧边栏-->
<Aside/>
<!--内容区域,表格, 这个部分是从 HomeView.vue 组件来的-->
<router-view style="flex: 1"/>
</div>
</div>
</template>
<style>
</style>
<script>
import Header from "@/components/Header";
import Aside from "@/components/Aside"; export default {
name: "Layout",
components: {
Header,
Aside
}
}
</script>

(9)项目的基本页面如下:

4.功能03-创建SpringBoot后端项目

4.1需求分析

项目前后端分离情况如下:分成两个子项目(前端和后端),现在来完成后端的子项目创建。

4.2代码实现

(1)创建maven项目,引入需要的依赖

<!--导入SpringBoot父工程-->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.5.3</version>
</parent> <dependencies>
<!--web starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.3</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!--配置处理器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--test starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--druid依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.17</version>
</dependency>
<!--mybatis-plus starter-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
</dependencies>

(2)application.yml中配置port和配置DB连接信息

server:
port: 9090
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_furn?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456

(3)主程序

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

测试启动,运行成功:

(4)配置数据源

package com.li.furn.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; /**
* @author 李
* @version 1.0
*/
@Configuration
public class DruidInitConfig {
@ConfigurationProperties("spring.datasource")
@Bean
public DataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
}

5.功能04-添加家居信息

5.1需求分析

在前端点击添加家居,弹出一个对话框,可以让我们填写家居的数据,填完之后点击确定,可以将数据发送到后端,然后保存到数据库表中。

5.2思路分析

  1. 完成后台代码从mapper->service->controller,并第每层代码进行测试,到controller这一层,使用postman发送http请求完成测试。

  2. 完成前台代码,使用axios发送json数据给后台,实现添加家居信息

5.3代码实现

5.3.1创建数据库和表

-- 创建数据库
DROP DATABASE IF EXISTS springboot_furn;
CREATE DATABASE springboot_furn;
USE springboot_furn; -- 创建表
CREATE TABLE furn(
`id` INT(11) PRIMARY KEY AUTO_INCREMENT,#id
`name` VARCHAR(64) NOT NULL,#家居名
`maker` VARCHAR(64) NOT NULL,#厂商
`price` DECIMAL(11,2) NOT NULL,#价格
`sales` INT(11) NOT NULL,#销量
`stock` INT(11) NOT NULL#库存
)CHARSET=utf8;

5.3.2工具类

(2)创建 com/li/furn/util/Result.java,该工具类用于返回结果(json 格式)

package com.li.furn.util;

/**
* @author 李
* @version 1.0
*/
public class Result<T> {
private String code;//状态码 200-success 400-fail
private String msg;//状态说明
private T data;//返回的数据,使用泛型 public Result() {
} public Result(T data) {
this.data = data;
} //返回需要的result对象,表示成功
public static Result success() {
Result result = new Result<>();
result.setCode("200");
result.setMsg("success");
return result;
} //返回成功的result对象,表示成功,同时携带数据
//如果需要在static方法中使用泛型,需要在static关键字后添加<T>
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>(data);
result.setCode("200");
result.setMsg("success");
return result;
} //返回需要的result对象-表示失败
//因为失败的原因有很多中,因此直接将其作为参数传进来
public static Result error(String code, String msg) {
Result result = new Result<>();
result.setCode(code);
result.setMsg(msg);
return result;
} //返回成功的result对象,表示失败,同时携带数据
public static <T> Result<T> error(String code, String msg, T data) {
Result<T> result = new Result<>(data);
result.setCode(code);
result.setMsg(msg);
return result;
} public String getCode() {
return code;
} public void setCode(String code) {
this.code = code;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} public T getData() {
return data;
} public void setData(T data) {
this.data = data;
}
}

5.3.3bean层

创建furn表映射的bean--Furn.java

package com.li.furn.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; /**
* @author 李
* @version 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Furn {
private Integer id;
private String name;
private String maker;
private double price;
private Integer sales;
private Integer stock;
}

5.3.4mapper层

创建funMapper.java接口

package com.li.furn.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.li.furn.bean.Furn;
import org.apache.ibatis.annotations.Mapper; /**
* @author 李
* @version 1.0
* 如果是MyBatisPlus,FurnMapper接口可以通过mp提供的BaseMapper接口来扩展功能
*/
//@Mapper 这里如果没有添加mapper注解,可以在主程序中指定扫描
public interface FurnMapper extends BaseMapper<Furn> {
}

如果使用@MapperScan(basePackages = "xxx") ,需要指定到确切的包

测试FurnMapper接口

package com.li.furn;

import com.li.furn.bean.Furn;
import com.li.furn.mapper.FurnMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest; import javax.annotation.Resource; /**
* @author 李
* @version 1.0
*/
//注意,测试时,如果测试的类和对应源码中的类的包名不同,需要手动指定
@SpringBootTest
public class FurnMapperTest {
//装配FurnMapper对象(实际上是该接口的代理对象)
@Resource
private FurnMapper furnMapper; @Test
public void furnMapperTest() {
Furn furn = furnMapper.selectById(1);
System.out.println("furn=" + furn);
}
}

测试结果:

5.3.5service层

FurnService接口:

package com.li.furn.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.li.furn.bean.Furn; /**
* @author 李
* @version 1.0
*/ public interface FurnService extends IService<Furn> {
}

FurnServiceImpl实现类:

package com.li.furn.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.li.furn.bean.Furn;
import com.li.furn.mapper.FurnMapper;
import com.li.furn.service.FurnService;
import org.springframework.stereotype.Service; /**
* @author 李
* @version 1.0
*/
@Service
public class FurnServiceImpl
extends ServiceImpl<FurnMapper, Furn>
implements FurnService {
}

service层测试:测试成功

package com.li.furn;
... @SpringBootTest
public class ApplicationTest {
@Resource
private FurnService furnService; @Test
public void furnServiceTest() {
List<Furn> furns = furnService.list();
for (Furn furn : furns) {
System.out.println("furn=" + furn);
}
}
}

5.3.6controller层

注意:如果是以表单形式提交数据,则不需要在参数前添加@RequestBody注解;如果使用了@RequestBody注解,要注意测试时,向后端发送的数据是json格式(Content-Type)。

package com.li.furn.controller;

import com.li.furn.bean.Furn;
import com.li.furn.service.FurnService;
import com.li.furn.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /**
* @author 李
* @version 1.0
* 因为当前项目为前后端分离,在默认情况下,前端发出请求
* 后端返回json数据,为了方便,我们就在类上使用@RestController
*/
@RestController//ResponseBody+Controller
@Slf4j
public class FurnController {
@Resource
private FurnService furnService; /**
* 完成添加添加家居信息的功能
*
* 1.因为前端发送的数据通常也是使用json格式的,
* 因此使用 @RequestBody 将前端提交的 json数据,封装成 Javabean 对象
* 2.如果前端是以表单形式提交的,则不能使用 @RequestBody
*
* @param furn
* @return
*/
@PostMapping("/save")
public Result save(@RequestBody Furn furn) {
log.info("furn={}", furn);
furnService.save(furn);
return Result.success();//返回成功数据
}
}

postman进行测试:(注意Headers中的Content-Type属性要指定为"application/json",否则会出错)

测试结果:

数据库显示插入成功:

5.3.7解决id自增长问题

furn表的id字段被设计为自增长,但是当实际插入数据时,如果没有给定id的值,底层执行的时候将会报错:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Could not set property 'id' of 'class com.li.furn.bean.Furn' with value '1640682391397732353' Cause: java.lang.IllegalArgumentException: argument type mismatch

这是因为底层没有获取到自增长字段的值。我们可以使用@TableId来解决,该注解可以标识表的主键,并且如果指定的是自增主键,会将自增主键值返回到实体类中。

Mybatis中需要使用 useGeneratedKeys,keyProperty,keyColumn 设置自增主键值的回返,在实体类对象中获取即可。在MybatisPlus中在进行数据新增时,在新增成功后,会自动的将自增的主键值返回到实体类对象中,前提是需要在实体类中使用@TableId表明主键字段,并且为自增类型。

5.3.8前端代码

(1)在前端项目中安装axios,用于发送ajax请求给后台:npm i axios -S

(2)创建工具文件src/utils/request.js,用于创建axios request对象

//引入axios
// 如果在启动前端项目,提示找不到axios,把光标放在import axios from 'axios' 的 'axios' 上
// 会有一个修复提示,导入 axios,点击导入即可正常使用
import axios from "axios";
//通过axios创建对象-request对象,用于发送请求到后端
const request = axios.create({
timeout: 5000
}) //对request拦截器的处理
//1.可以对请求做统一的处理
//2.比如统一地加入token,Content-Type等
request.interceptors.request.use(
config => {
config.headers['Content-Type'] = 'application/json;charset=uft-8';
return config;
},
error => {
return Promise.reject(error)
}) //导出request对象
export default request;

(3)在Home.vue中添加表单,添加添加按钮,可以出现添加家居的对话框:代码略

(4)解决跨域问题

浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。在前后端分离的模式下,前后端的域名是不一致的,此时就会发生跨域访问问题。在请求的过程中我们要想回去数据一般都post/get请求,所以跨域问题出现。

解决跨域问题的方案很多,这里在vue.config.js文件中修改跨域配置来解决:

const {defineConfig} = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
})
module.exports = {
devServer: {
port: 10000,//启动端口
proxy: {//设置代理
'api/': {//设置拦截器 拦截器格式(斜杠+拦截器名字)
target: 'http://localhost:9090',//目标地址(后端地址)
changeOrigin: true,//是否设置同源,实现跨域
pathRewrite: {//路径重写
'/api': ''//选择忽略拦截器里面的单词
}
}
}
}
}

注意,设置之后需要重新启动前端项目。

注意两点问题:

  1. 一定要确定 request.post("/api/save") 替换后是项目后台服务对应提供的API接口url,否则报404错误
  2. 当执行跨域请求时,如果浏览器仍然提示 http://localhost:9090/api/xxx

day01-项目介绍和功能实现的更多相关文章

  1. Android Hotpatch系列之-项目介绍

    给现实Android apk打补丁,不用强迫客户升级客户端,悄悄的就把bug修复了,程序猿再也不用被老大骂娘了. 客户端例子实现:https://github.com/fengcunhan/Hotpa ...

  2. 揭开webRTC媒体服务器的神秘面纱——WebRTC媒体服务器&开源项目介绍

    揭开webRTC媒体服务器的神秘面纱--WebRTC媒体服务器&开源项目介绍 WebRTC生态系统是非常庞大的.当我第一次尝试理解WebRTC时,网络资源之多让人难以置信.本文针对webRTC ...

  3. windows下nodejs express安装及入门网站,视频资料,开源项目介绍

    windows下nodejs express安装及入门网站,视频资料,开源项目介绍,pm2,supervisor,npm,Pomelo,Grunt安装使用注意事项等总结 第一步:下载安装文件下载地址: ...

  4. [转]基于C#的开源GIS项目介绍之SharpMap篇

    我是一个刚毕业的GIS本科毕业生,目前在杭州从事GIS软件应用开发.在项目开发中总感觉自己的编程水平还不够,于是想找些开源GIS小项目来研究研究,借以提高自己的编程能力和项目开发能力.在网上搜了一下“ ...

  5. 项目介绍4 y有用

    在青岛做了两年开发,大大小小参与过三个项目的开发,一个是某公司内部的人员管理系统,一个是物流项目,最近做的是一个电商项目. 前两个项目采用的是ssh框架搭建的,最近的项目采用的是ssm框架搭建的.在实 ...

  6. 【转】一个Android项目搞定所有主流架构-1.项目介绍和基本MVC架构示例

    http://www.jianshu.com/p/798536fb91c5 项目启发来自谷歌的同类框架项目https://github.com/googlesamples/android-archit ...

  7. OpenLayers项目分析——(一)项目介绍

    OpenLayers 是由MetaCarta公司开发的,用于WebGIS客户端的JavaScript包,目前的最高版本是2.7 V,通过BSD License 发行.它实现访问地理空间数据的方法都符合 ...

  8. LVS项目介绍

    LVS项目介绍 章文嵩 (wensong@linux-vs.org) 转自LVS官方参考资料 2002 年 3 月 本文介绍了Linux服务器集群系统--LVS(Linux Virtual Serve ...

  9. Android项目实战之高仿网易云音乐项目介绍

    这一节我们来讲解这个项目所用到的一些技术,以及一些实现的效果图,让大家对该项目有一个整体的认识,推荐大家收藏该文章,因为我们发布文章后会在该文章里面加入链接,这样大家找着就很方便. 目录 第1章 前期 ...

  10. WeChair Plus版项目介绍

    这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 团队名称 WeChair 这个作业要求在哪里 团队作业第一次:团队作业第一次(2) 这个作业的目标 项目介绍,项目修改 作业正文 ...

随机推荐

  1. 【路由器】电信光猫中兴 F7010C 折腾记录

    目录 问题描述 解锁超管密码 前言 配置安卓抓包环境 抓包获取超管密码 IPv6 配置 光猫拨号 改用 SLAAC 路由器配置 wan6 配置 wan 配置 lan 配置 验证 参考资料 问题描述 近 ...

  2. Build 和 Compile 区别

  3. Cnpack ctrl+alt+v 来回切换 变量声明区,和代码写区,非常方便

    Cnpack ctrl+alt+v 来回切换 变量声明区,和代码写区,非常方便 非常方便

  4. 【CAS学习一】CAS服务端部署

    公司要做单点登录系统,网上搜了一下目前主流方案是CAS,故部署一个试试看. 1.下载 因为最近出现log4j2远程代码执行漏洞,尽量选择新版本已修复此漏洞的,故CAS选择6.4版本.打包部署依赖JDK ...

  5. 《ASP.NET Core 微服务实战》-- 读书笔记(第7章)

    第 7 章 开发 ASP.NET Core Web 应用 ASP.NET Core 基础 在本章,我们将从一个命令行应用开始,并且在不借助任何模板,脚手架和向导的情况下,最终得到一个功能完整的 Web ...

  6. 测距工具部分情况下无效的问题解决 - 高德JSAPI

    最近项目中新增了一个需求是在地图上新增一个测距工具,方便看一下距离 高德官方本身自带了有一个测距工具类的 RangingTool ,以插件的方式引入即可 问题一: 如果地图上有覆盖物的话(我这是 po ...

  7. 到什么程度才叫精通 Linux?

    大家好,我是陶朱公Boy,一个认真生活,总想超越自己的程序员. 前言 知乎上有一个提问:到什么程度才叫精通 Linux?                              ↓↓↓ 今天,我们就 ...

  8. burpsuit+adb+逍遥模拟器

    安卓7之后,单纯的将burpsuit的证书导出手动安装到模拟器中已经不行了,app可以只信任指定证书和系统内置的证书,后续用户安装的证书是不生效的,只能想办法装到系统内部 需要将证书通过openssl ...

  9. js获取格式化日期方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. win32 - 按文件的创建日期排序

    因项目中使用文件的创建日期来命名文件,所以不用额外查找文件的创建日期再进行排序,记录一下 bool AscendingSortByCreationTime(const std::wstring& ...