- 前端:vue + spa + axios
- 后端:spring cloud + nacos + gateway + ssm+
1.环境搭建
1.0 数据库
#学生数据库
CREATE DATABASE nacos_ssm_student;
USE nacos_ssm_student;
CREATE TABLE tb_city(
c_id VARCHAR(32) PRIMARY KEY COMMENT '城市ID',
city_name VARCHAR(20) COMMENT '城市名称' ,
parent_id VARCHAR(32) COMMENT '父ID'
);
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('320000','江苏省','0');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140000','山西省','0');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('130000','河北省','0');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('320100','南京市','320000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('320102','玄武区','320100');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('320103','白下区','320100');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('321300','宿迁市','320000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('321322','沭阳县','321300');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('321323','泗阳县','321300');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140100','太原市','140000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140106','迎泽区','140100');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140108','尖草坪区','140100');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140800','运城市','140000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140823','闻喜县','140800');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140828','夏 县','140800');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('130100','石家庄市','130000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('130127','高邑县','130100');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('130185','鹿泉市','130100');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('131000','廊坊市','130000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('131003','广阳区','131000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('131022','固安县','131000');
CREATE TABLE `tb_student` (
`s_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '学生ID',
`sname` VARCHAR(50) DEFAULT NULL COMMENT '姓名',
`age` INT(11) DEFAULT NULL COMMENT '年龄',
`birthday` DATETIME DEFAULT NULL COMMENT '生日',
`gender` CHAR(1) DEFAULT NULL COMMENT '性别',
`c_id` INT DEFAULT NULL,
`city_ids` VARCHAR(32) DEFAULT NULL COMMENT '城市:320000,321300,321322'
);
INSERT INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (1,'赵三33',21,'2001-01-17 00:00:00','1',1,'320000,321300,321322');
INSERT INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (2,'钱四444',1900,'2001-05-16 00:00:00','1',2,'320000,321300,321322');
INSERT INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (3,'孙五56',189,'2022-03-15 00:00:00','0',1,'320000,321300,321322');
INSERT INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (4,'张三',20,'2020-12-21 00:00:00','0',2,'320000,321300,321322');
INSERT INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (5,'xxx',18,'2020-12-21 00:00:00','0',2,'140000,140800,140823');
INSERT INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (6,'123',18,'2020-11-01 00:00:00','0',3,'130000,130100,130127');
INSERT INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (7,'xx',18,'2020-11-02 00:00:00','0',1,'130000,131000,131003');
1.1 后端环境
1.1.1 父项目
-
坐标
<!-- 1 确定spring boot的版本--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> </parent> <!--2 确定版本--> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <spring-cloud-release.version>Hoxton.SR3</spring-cloud-release.version> <nacos.version>1.1.0</nacos.version> <alibaba.cloud.version>2.2.1.RELEASE</alibaba.cloud.version> <mybatis.starter.version>1.3.2</mybatis.starter.version> <mapper.starter.version>2.0.2</mapper.starter.version> <mysql.version>5.1.32</mysql.version> <pageHelper.starter.version>1.2.5</pageHelper.starter.version> <durid.starter.version>1.1.10</durid.starter.version> <swagger.version>2.7.0</swagger.version> <jwt.jjwt.version>0.9.0</jwt.jjwt.version> <jwt.joda.version>2.9.7</jwt.joda.version> <beanutils.version>1.9.3</beanutils.version> <student.version>1.0-SNAPSHOT</student.version> </properties> <!-- 3 锁定版本--> <dependencyManagement> <dependencies> <!-- sprig cloud--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud-release.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--nacos --> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>${nacos.version}</version> </dependency> <!--nacos cloud 发现 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>${alibaba.cloud.version}</version> </dependency> <!--nacos cloud 配置 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>${alibaba.cloud.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-sentinel --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>${alibaba.cloud.version}</version> </dependency> <!-- mybatis plus启动器 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-annotation</artifactId> <version>3.4.0</version> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- Druid连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${durid.starter.version}</version> </dependency> <!--swagger2--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.version}</version> </dependency> <!--jwt--> <!--JavaBean工具类,用于JavaBean数据封装--> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>${beanutils.version}</version> </dependency> <!--jwt工具--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jwt.jjwt.version}</version> </dependency> <!--joda 时间工具类 --> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>${jwt.joda.version}</version> </dependency> <!-- 自定义项目 --> <dependency> <groupId>com.czxy</groupId> <artifactId>nacos-ssm-fx-domain-bg12</artifactId> <version>${student.version}</version> </dependency> </dependencies> </dependencyManagement>
1.1.2 domain项目
-
坐标
<dependencies> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--jackson--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-json</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-annotation</artifactId> </dependency> </dependencies> -
JavaBean
package com.czxy.domain; 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.util.Date; @TableName("tb_student") @Data public class Student { @TableId("s_id") private Integer sid; @TableField("sname") private String sname; @TableField("age") private Integer age; @TableField("birthday") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private Date birthday; @TableField("gender") private String gender; @TableField("c_id") private Integer cid; @TableField("city_ids") private String cityIds; } /* CREATE TABLE `tb_student` ( `s_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '学生ID', `sname` VARCHAR(50) DEFAULT NULL COMMENT '姓名', `age` INT(11) DEFAULT NULL COMMENT '年龄', `birthday` DATETIME DEFAULT NULL COMMENT '生日', `gender` CHAR(1) DEFAULT NULL COMMENT '性别', `c_id` INT DEFAULT NULL, `city_ids` VARCHAR(32) DEFAULT NULL COMMENT '城市:320000,321300,321322' ); */ -
拷贝:BaseResult
package com.czxy.vo; import lombok.Getter; import java.util.HashMap; import java.util.Map; @Getter public class BaseResult<T> { //成功状态码 public static final int OK = 20000; //失败状态码 public static final int ERROR = 0; //返回码 private Integer code; //返回消息 private String message; //存放数据 private T data; //其他数据 private Map<String,Object> other = new HashMap<>(); public BaseResult() { } public BaseResult(Integer code, String message) { this.code = code; this.message = message; } public BaseResult(Integer code, String message, T data) { this.code = code; this.message = message; this.data = data; } /** * 快捷成功BaseResult对象 * @param message * @return */ public static BaseResult ok(String message){ return new BaseResult(BaseResult.OK , message); } public static BaseResult ok(String message, Object data){ return new BaseResult(BaseResult.OK , message, data ); } /** * 快捷失败BaseResult对象 * @param message * @return */ public static BaseResult error(String message){ return new BaseResult(BaseResult.ERROR , message); } /** * 自定义数据区域 * @param key * @param msg * @return */ public BaseResult append(String key , Object msg){ other.put(key , msg); return this; } // public Integer getCode() { // return code; // } // // public String getMessage() { // return message; // } // // public T getData() { // return data; // } // // public Map<String, Object> getOther() { // return other; // } }
1.1.3 网关gateway
-
坐标
<dependencies> <!-- 网关 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- nacos 服务发现 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--JavaBean工具类,用于JavaBean数据封装--> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> </dependency> <!--jwt工具--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency> <!--joda 时间工具类 --> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> </dependency> </dependencies> -
yml配置文件:application.yml
#端口号 server: port: 10010 spring: application: name: student-gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 #nacos服务地址 gateway: discovery: locator: enabled: true #开启服务注册和发现的功能,自动创建router以服务名开头的请求路径转发到对应的服务 lowerCaseServiceId: true #将请求路径上的服务名配置为小写 -
启动类
package com.czxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient //服务发现 public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class,args); } } -
跨域配置类:
config/GlobalGatewayCorsConfig.javapackage com.czxy.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.cors.reactive.CorsUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; @Configuration public class GlobalGatewayCorsConfig { @Bean public WebFilter corsFilter2() { return (ServerWebExchange ctx, WebFilterChain chain) -> { ServerHttpRequest request = ctx.getRequest(); if (CorsUtils.isCorsRequest(request)) { HttpHeaders requestHeaders = request.getHeaders(); ServerHttpResponse response = ctx.getResponse(); HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); HttpHeaders headers = response.getHeaders(); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin()); headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders()); if (requestMethod != null) { headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name()); } headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*"); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); return Mono.empty(); } } return chain.filter(ctx); }; } }
1.1.4 学生服务
-
坐标
<dependencies> <!--web起步依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- nacos 客户端 --> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> </dependency> <!-- nacos 服务发现 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- mybatis plus启动器 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Druid连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> </dependency> <!--swagger2--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> </dependency> <!-- feign 远程调用 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- 自定义项目 --> <dependency> <groupId>com.czxy</groupId> <artifactId>nacos-ssm-fx-domain-bg12</artifactId> </dependency> </dependencies> -
yml配置文件
#端口号 server: port: 9001 spring: application: name: student-plus-service #服务名 datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/nacos_ssm_student?useUnicode=true&characterEncoding=utf8 username: root password: 1234 druid: #druid 连接池配置 initial-size: 1 #初始化连接池大小 min-idle: 1 #最小连接数 max-active: 20 #最大连接数 test-on-borrow: true #获取连接时候验证,会影响性能 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 #nacos服务地址 sentinel: transport: dashboard: 127.0.0.1:8080 -
启动类
package com.czxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class StudentServiceApplication { public static void main(String[] args) { SpringApplication.run(StudentServiceApplication.class,args); } } -
配置类:
config/Swagger2ConfigurationV3.javapackage com.czxy.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.*; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; import java.util.List; /** * Swagger2 配置类, * 访问路径:swagger-ui.html * 自动注册: * 位置:resources/META-INF/spring.factories * 内容: * org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ * com.czxy.config.Swagger2Configuration */ @Configuration @EnableSwagger2 public class Swagger2ConfigurationV3 { @Bean public Docket createRestApi() { // 1 确定文档Swagger版本 Docket docket = new Docket(DocumentationType.SWAGGER_2); // 2 设置 api基本信息 docket.apiInfo(apiInfo()); // 3 设置自定义加载路径 docket = docket.select() .apis(RequestHandlerSelectors.basePackage("com.czxy")) .paths(PathSelectors.any()) .build(); //4 设置权限 docket.securitySchemes(securitySchemes()); docket.securityContexts(securityContexts()); return docket; } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("API") .description("基于swagger接口文档") .contact(new Contact("梁桐","http://www.javaliang.com","liangtong@itcast.cn")) .version("1.0") .build(); } private List<ApiKey> securitySchemes() { List<ApiKey> list = new ArrayList<>(); // name 为参数名 keyname是页面传值显示的 keyname, name在swagger鉴权中使用 list.add(new ApiKey("Authorization", "Authorization", "header")); return list; } private List<SecurityContext> securityContexts() { List<SecurityContext> list = new ArrayList<>(); list.add(SecurityContext.builder() .securityReferences(defaultAuth()) .forPaths(PathSelectors.regex("^(?!auth).*$")) .build()); return list; } private List<SecurityReference> defaultAuth() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; List<SecurityReference> list = new ArrayList(); list.add(new SecurityReference("Authorization", authorizationScopes)); return list; } }
1.2 前端环境
1.2.1 创建项目:
vue create nacos-fx-spa-bg12
1.2.2 整合axios
-
下载axios
cnpm install axios --save -
抽取工具 request.js
npm i element-ui --savesrc/utils/request.jsimport axios from 'axios' import { MessageBox, Message } from 'element-ui' // 方式1:设置基本路径 // axios.defaults.baseURL='http://localhost:10010/api' // 方式2:create an axios instance,并设置基本路径 const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url // withCredentials: true, // send cookies when cross-domain requests timeout: 5000 // request timeout }) // request interceptor service.interceptors.request.use( config => { // 请求头中追加token let token = localStorage.getItem('token') if (token) { config.headers.Authorization = token } return config }, error => { // do something with request error console.log(error) // for debug return Promise.reject(error) } ) // response interceptor service.interceptors.response.use( response => { const res = response.data // if the custom code is not 20000, it is judged as an error. if (res.code !== 20000) { Message({ message: res.message || 'Error', type: 'error', duration: 5 * 1000 }) // ajax异常提示信息 (路径信息,数据) console.info(response.config, response.data ) return Promise.reject(new Error(res.message || 'Error')) } else { return res } }, error => { console.log('err' + error) // for debug if(error.response.status == 401) { MessageBox.confirm(error.response.data, '重新登录确认框', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => { // 删除token localStorage.removeItem('token') location.reload() }) } else { Message({ message: error.message, type: 'error', duration: 5 * 1000 }) } return Promise.reject(error) } ) export default service -
抽取api:
-
将ajax抽取到一个student.js文件中,student.js调用request.js(使用增强后的axios)
// 导入工具 request.js import axios from '@/utils/request.js' // 编写功能方法 export function selectAll() { return axios.get('/student-plus-service/student') } -
request.js ajax访问路径的前缀baseURL,抽取到配置文件中
.env.development
-
~~~
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = 'http://localhost:10010/'
~~~
2. 学生管理
2.1 查询所有的学生
2.1.1 后端
-
步骤:
- 步骤1:编写mapper,通用mapper
- 步骤2:编写service,通用service 接口 + 实现类
- 步骤3:编写controller
-
步骤1:编写mapper,通用mapper
package com.czxy.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.czxy.domain.Student; import org.apache.ibatis.annotations.Mapper; @Mapper public interface StudentMapper extends BaseMapper<Student> { } -
步骤2:编写service,通用service 接口 + 实现类
-
接口
package com.czxy.service; import com.baomidou.mybatisplus.extension.service.IService; import com.czxy.domain.Student; public interface StudentService extends IService<Student> { } -
实现类
package com.czxy.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.czxy.domain.Student; import com.czxy.mapper.StudentMapper; import com.czxy.service.StudentService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService { }
-
-
步骤3:编写controller, GET请求 + BaseResult
package com.czxy.controller; import com.czxy.domain.Student; import com.czxy.service.StudentService; import com.czxy.vo.BaseResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; @RestController @RequestMapping("/student") public class StudentController { @Resource private StudentService studentService; @GetMapping public BaseResult selectAll() { // 1.请求数据 // 2 查询 List<Student> list = studentService.list(); // 3 响应结果 return BaseResult.ok("查询成功", list); /* BaesResult baseResult = new BaseResult(); baseResult.setCode(20000); //自定义编码 baseResult.setMessage("查询成功"); //提示信息 baseResult.setData( list ); //结果数据 */ } }
2.1.2 前端
1)访问页面
-
步骤1:修改App.vue页面,确定访问路径
<template> <div id="app"> <!-- 导航条,切换路由 --> <div id="nav"> <router-link to="/">Home</router-link> | <router-link to="/studentList">学生列表</router-link> </div> <!-- 路由视图,用于显示内容 --> <router-view/> </div> </template> <style> </style> -
步骤2:修改路由
src/router/index.js编写访问路径import Home from '../views/Home.vue' const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/studentList', name: '学生列表', component: () => import('../views/StudentList.vue') } ] -
步骤3:创建StudentList.vue页面
<template> <div> 学生列表页面 </div> </template> <script> export default { } </script> <style> </style>
2)显示查询结果
-
步骤:
- 步骤1:导入api,获得查询所有函数
- 步骤2:编写查询所有学生函数,调用导入api函数,完成ajax操作,查询结果保存studentList
- 步骤3:页面加载成功后,查询
- 步骤4:遍历展示
<template>
<div>
<!-- 4 展示数据 -->
<table border="1">
<tr>
<td>编号</td>
<td>姓名</td>
<td>年龄</td>
<td>生日</td>
<td>性别</td>
<td>班级</td>
<td>操作</td>
</tr>
<tr v-for="(student,index) in studentList" :key="index">
<td>{{student.sid}}</td>
<td>{{student.sname}}</td>
<td>{{student.age}}</td>
<td>{{student.birthday}}</td>
<td>{{student.gender == 1 ? '男' : '女'}}</td>
<td>{{student.cid}}</td>
<td>
修改
删除
</td>
</tr>
</table>
</div>
</template>
<script>
//1 导入查询函数
import {selectAll} from '../api/student'
export default {
data() {
return {
studentList: []
}
},
methods: {
async selectAllStudent() {
//2 ajax查询 -- request.js 中对响应结果response进行再处理,返回的是 response.data
let {data} = await selectAll() // {data} 从 baseResult中结果data,也就是查询结果
// 将查询结果保存数据区域
this.studentList = data
}
},
mounted() {
// 3 页面加载成功,查询所有
this.selectAllStudent()
},
}
</script>
<style>
</style>
2.2 条件查询 + 分页
2.2.1 后端步骤
-
确定访问路径
http://localhost:10010/student-plus-service/student/condition/{size}/{current} -
步骤1:准备条件封装StudentVo
-
步骤2:编写controller,获得分页参数+条件,返回 Page进行结果封装
-
步骤3:编写service
- 1)查询条件
- 2)分页
- 3)查询
- 4)关联
- 5)处理/返回结果
-
步骤4:拷贝MyBatisPlus分页配置类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pEssSDxP-1645576553138)(assets/image-20220222150608792.png)]
2.2.2 后端实现
-
步骤1:准备条件封装StudentVo
package com.czxy.vo; import lombok.Data; @Data public class StudentVo { private String cid; private String sname; private String startAge; private String endAge; } -
步骤2:编写controller,获得分页参数+条件,返回 Page进行结果封装
/** * * @param studentVo 条件 * @param size 每页个数 * @param current 第几页 * @return */ @PostMapping("/condtion/{size}/{current}") public BaseResult condition( @RequestBody StudentVo studentVo, @PathVariable("size") Integer size, @PathVariable("current") Integer current ){ // 2 查询 Page<Student> page = studentService.condition(studentVo,size,current); // 3 返回 return BaseResult.ok("查询成功", page); } -
步骤3:编写service
-
接口
package com.czxy.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.czxy.domain.Student; import com.czxy.vo.StudentVo; public interface StudentService extends IService<Student> { /** * 分页 + 条件 查询 * @param studentVo * @param size * @param current * @return */ Page<Student> condition(StudentVo studentVo, Integer size, Integer current); } -
实现类
@Override public Page<Student> condition(StudentVo studentVo, Integer size, Integer current) { //1 条件 QueryWrapper<Student> queryWrapper = new QueryWrapper<>(); // 1.1 班级 queryWrapper.eq(StringUtils.isNotBlank(studentVo.getCid()), "c_id", studentVo.getCid()); // 1.2 姓名 - like %张% queryWrapper.like(StringUtils.isNotBlank(studentVo.getSname()),"sname", studentVo.getSname()); // 1.3 开始年龄 queryWrapper.ge(StringUtils.isNotBlank(studentVo.getStartAge()),"age", studentVo.getStartAge()); // 1.4 结束年龄 queryWrapper.le(StringUtils.isNotBlank(studentVo.getEndAge()),"age", studentVo.getEndAge()); // 2 分页 Page page = new Page(current, size); // 3 查询 this.baseMapper.selectPage(page, queryWrapper); //TODO 4 关联--查询班级 // 5 返回 return page; }
-
-
步骤4:拷贝MyBatisPlus分页配置类
package com.czxy.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; import org.springframework.context.annotation.Configuration; @Configuration public class MybatisPlusConfig { /** * 配置插件 * @return */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); // 分页插件 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return mybatisPlusInterceptor; } }
2.2.3 前端步骤
-
步骤1:编写页面 StudentCondition.vue + 路由
-
步骤2:编写ajax student.js 写 condition函数
-
步骤3:修改StudentCondition.vue
- 基本查询:page、studentVo
- 条件查询
- 分页查询
2.2.4 前端实现
- 步骤1:编写页面 StudentCondition.vue + 路由
- 步骤2:编写ajax student.js 写 condition函数
// 查询所有学生+条件+分页
export function condition(page,studentVo) {
var url = `/student-plus-service/student/condtion/${page.size}/${page.current}`
return axios.post(url, studentVo)
}
-
步骤3:修改StudentCondition.vue
-
基本查询:page、studentVo
<template> <div> <!-- 列表展示 --> <table border="1"> <tr> <td>编号</td> <td>姓名</td> <td>年龄</td> <td>生日</td> <td>性别</td> <td>班级</td> <td>操作</td> </tr> <tr v-for="(student,index) in page.records" :key="index"> <td>{{student.sid}}</td> <td>{{student.sname}}</td> <td>{{student.age}}</td> <td>{{student.birthday}}</td> <td>{{student.gender == 1 ? '男' : '女'}}</td> <td>{{student.cid}}</td> <td> 修改 删除 </td> </tr> </table> </div> </template> <script> // 导入ajax函数 import {condition} from '../api/student' export default { data() { return { page: { //分页 size: 3, current: 1 }, studentVo: { //条件 cid: '', sname: '', startAge: '', endAge: '', } } }, methods: { async conditionFn(num) { // 设置第几页 if(num) { this.page.current = num } // ajax查询 let { data } = await condition(this.page, this.studentVo) // 获得结果 this.page = data } }, mounted() { // 查询第一页 this.conditionFn(1) }, } </script> <style> </style> -
条件查询:(使用模拟数据显示班级列表)
classesList: [ //班级的模拟数据 {cid:1, cname: 'Java56'}, {cid:2, cname: 'Java78'}, {cid:3, cname: 'Java12'}, {cid:4, cname: 'Java34'}, ]<!-- 条件查询表单 --> 班级 <select v-model="studentVo.cid"> <option value="">--选择班级--</option> <option v-for="(classes,index) in classesList" :key="index" :value="classes.cid">{{classes.cname}}</option> </select> 姓名:<input type="text" size="8" v-model="studentVo.sname"/> 年龄:<input type="text" size="8" v-model="studentVo.startAge"/> -- <input type="text" size="8" v-model="studentVo.endAge"/> <input type="button" value="查询" @click="conditionFn(1)" /><!--条件查询的完整版--> <template> <div> <!-- 条件查询 --> 班级 <select v-model="studentVo.cid"> <option value="">--选择班级--</option> <option v-for="(classes,index) in classesList" :key="index" :value="classes.cid">{{classes.cname}}</option> </select> 姓名:<input type="text" size="8" v-model="studentVo.sname"/> 年龄:<input type="text" size="8" v-model="studentVo.startAge"/> -- <input type="text" size="8" v-model="studentVo.endAge"/> <input type="button" value="查询" @click="conditionFn(1)" /> <!-- 列表展示 --> <table border="1"> <tr> <td>编号</td> <td>姓名</td> <td>年龄</td> <td>生日</td> <td>性别</td> <td>班级</td> <td>操作</td> </tr> <tr v-for="(student,index) in page.records" :key="index"> <td>{{student.sid}}</td> <td>{{student.sname}}</td> <td>{{student.age}}</td> <td>{{student.birthday}}</td> <td>{{student.gender == 1 ? '男' : '女'}}</td> <td>{{student.cid}}</td> <td> 修改 删除 </td> </tr> </table> </div> </template> <script> // 导入ajax函数 import {condition} from '../api/student' export default { data() { return { page: { //分页 size: 3, current: 1 }, studentVo: { //条件 cid: '', sname: '', startAge: '', endAge: '', }, classesList: [ //班级的模拟数据 {cid:1, cname: 'Java56'}, {cid:2, cname: 'Java78'}, {cid:3, cname: 'Java12'}, {cid:4, cname: 'Java34'}, ] } }, methods: { async conditionFn(num) { // 设置第几页 if(num) { this.page.current = num } // ajax查询 let { data } = await condition(this.page, this.studentVo) // 获得结果 this.page = data } }, mounted() { // 查询第一页 this.conditionFn(1) }, } </script> <style> </style> -
分页查询
<!-- 分页条 --> 每页 <select v-model="page.size" @change="conditionFn(1)"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="5">5</option> <option value="10">10</option> </select> 条, <a href="" @click.prevent="conditionFn(num)" v-for="(num,index) in page.pages" :key="index">{{num}}</a>, 跳转到第 <input type="text" size="4" v-model="page.current" @keyup.enter="conditionFn()"> 页
-
2.2.5 前端完整代码
<template>
<div>
<!-- 条件查询 -->
班级 <select v-model="studentVo.cid">
<option value="">--选择班级--</option>
<option v-for="(classes,index) in classesList" :key="index" :value="classes.cid">{{classes.cname}}</option>
</select>
姓名:<input type="text" size="8" v-model="studentVo.sname"/>
年龄:<input type="text" size="8" v-model="studentVo.startAge"/> --
<input type="text" size="8" v-model="studentVo.endAge"/>
<input type="button" value="查询" @click="conditionFn(1)" />
<!-- 列表展示 -->
<table border="1">
<tr>
<td>编号</td>
<td>姓名</td>
<td>年龄</td>
<td>生日</td>
<td>性别</td>
<td>班级</td>
<td>操作</td>
</tr>
<tr v-for="(student,index) in page.records" :key="index">
<td>{{student.sid}}</td>
<td>{{student.sname}}</td>
<td>{{student.age}}</td>
<td>{{student.birthday}}</td>
<td>{{student.gender == 1 ? '男' : '女'}}</td>
<td>{{student.cid}}</td>
<td>
修改
删除
</td>
</tr>
</table>
<!-- 分页条 -->
每页
<select v-model="page.size" @change="conditionFn(1)">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="5">5</option>
<option value="10">10</option>
</select>
条,
<a href="" @click.prevent="conditionFn(num)" v-for="(num,index) in page.pages" :key="index">{{num}}</a>,
跳转到第
<input type="text" size="4" v-model="page.current" @keyup.enter="conditionFn()">
页
</div>
</template>
<script>
// 导入ajax函数
import {condition} from '../api/student'
export default {
data() {
return {
page: { //分页
size: 3,
current: 1
},
studentVo: { //条件
cid: '',
sname: '',
startAge: '',
endAge: '',
},
classesList: [ //班级的模拟数据
{cid:1, cname: 'Java56'},
{cid:2, cname: 'Java78'},
{cid:3, cname: 'Java12'},
{cid:4, cname: 'Java34'},
]
}
},
methods: {
async conditionFn(num) {
// 设置第几页
if(num) {
this.page.current = num
}
// ajax查询
let { data } = await condition(this.page, this.studentVo)
// 获得结果
this.page = data
}
},
mounted() {
// 查询第一页
this.conditionFn(1)
},
}
</script>
<style>
</style>
2.3 添加或修改
2.3.1 后端实现
@PostMapping
public BaseResult saveOrUpdate(@RequestBody Student student) {
try {
// 保存或更新:如果没有id进行添加操作;如果有id进行更新操作
boolean result = studentService.saveOrUpdate(student);
//处理
if(result) {
return BaseResult.ok("编辑成功");
}
return BaseResult.error("编辑失败");
} catch (Exception e) {
e.printStackTrace();
return BaseResult.error(e.getMessage());
}
}
- 数据库的id为自动增强,如果JavaBean没有设置,会出现
类型不匹配异常。
3. 班级管理
3.1 查询所有班级
3.1.1 后端
-
步骤:
- 步骤1:编写JavaBean,Classes
- 步骤2:编写Mapper,ClassesMapper,实现通用mapper
- 步骤3:编写service,接口+实现类+通用
- 步骤4:编写controller
-
步骤1:编写JavaBean,Classes
package com.czxy.domain; 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 lombok.Data; @TableName("tb_class") @Data public class Classes { @TableId(value = "cid", type = IdType.AUTO) private Integer cid; @TableField("cname") private String cname; } /* CREATE TABLE `tb_class` ( `cid` int(11) NOT NULL AUTO_INCREMENT, `cname` varchar(50) DEFAULT NULL, PRIMARY KEY (`cid`) ) */ -
步骤2:编写Mapper,ClassesMapper,实现通用mapper
package com.czxy.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.czxy.domain.Classes; import org.apache.ibatis.annotations.Mapper; @Mapper public interface ClassesMapper extends BaseMapper<Classes> { } -
步骤3:编写service,接口+实现类+通用
-
接口
package com.czxy.service; import com.baomidou.mybatisplus.extension.service.IService; import com.czxy.domain.Classes; public interface ClassesService extends IService<Classes> { } -
实现类
package com.czxy.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.czxy.domain.Classes; import com.czxy.mapper.ClassesMapper; import com.czxy.service.ClassesService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional public class ClassesServiceImpl extends ServiceImpl<ClassesMapper, Classes> implements ClassesService { }
-
-
步骤4:编写controller
package com.czxy.controller; import com.czxy.domain.Classes; import com.czxy.service.ClassesService; import com.czxy.vo.BaseResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; @RestController @RequestMapping("/classes") public class ClassesController { @Resource private ClassesService classesService; /** * 查询所有 * @return */ @GetMapping public BaseResult findAll() { // 2 查询 List<Classes> list = classesService.list(); // 3 返回 return BaseResult.ok("查询成功", list ); } }