目录
项目搭建
内容介绍
1. 项目介绍; (了解)
2. 需求分析; (了解)
3. 项目架构; (掌握)
4. 后端项目搭建; (掌握)
5. swagger (掌握)
6. postman测试 (掌握)
需求分析 需求设计(项目架构)开发 测试 上线
1.项目介绍
-
本项目是一个(Online To Offline)以宠物为核心打造的宠物乐园o2o项目。随着生活质量提供,人们不再满足简单物质生活,还追求更高层次精神生活。很多人愿意有养宠物意愿,愿意为宠物消费,正是基于这种场景,我们才开发了这个项目。首先让用户领养宠物,然后针对用户的宠物提供上门洗澡,美容,寄养,购买商品,宠物百科等综合服务平台。由用户下单,平台统一分派给线下门店上门服务。平台除了提供针对普通用户的基本需求功能,支持商家入驻,合作加盟,扩展线下门店渠道。
-
O2o:通过互联网手段挖掘机会,最终要到线下消费。
汽车之家 房屋之家 育儿 婚恋等
2.需求分析
3.项目架构
3.1.项目技术架构
后端架构: springboot+ ssm+
echart+ quartz+
Javaemail+
Easypoi+redis
前端架构: vue技术栈:nodejs npm webpack vue vue-cli elementui
服务器: linux+nginx+docker
数据存储: mysql +redis+fastdfs
第三方登录 微信 微博 QQ
第三方支付 支付宝扫描支付
第三方短信接口 中国网建
今天:后端项目搭建
明天:前后端整合
3.2.前后端分离
3.2.1. 什么是前后端分离
在传统的web应用开发中,大多数的程序员会将浏览器作为前后端的分界线。将浏览器中为用户进行页面展示的部分称之为前端,而将运行在服务器,为前端提供业务逻辑和数据准备的所有代码统称为后端。
很多人误以为前后端分离只是一种web应用开发模式,只要在web应用的开发期进行了前后端开发工作的分工就是前后端分离。 前后端分工
其实前后端分离并不只是开发模式,而是web应用的一种架构模式。在开发阶段,前后端工程师约定好数据交互接口,实现并行架构,开发和测试;在运行阶段前后端分离模式需要对web应用进行分别部署,前后端之前使用HTTP或者其他协议进行交互请求。然而作为一种架构模式,我们在实施的过程中主要对以下四个方面来进行比较和重新认识。
前后端分离大概可以从以下方面来理解:
3.2.2.交互形式
在前后端分离架构中,后端只需要负责按照约定的数据格式向前端提供可调用的API服务即可。前后端之间通过HTTP请求进行交互,前端获取到数据后,进行页面的组装和渲染,页面跳转,最终返回给浏览器。
3.2.3.代码组织方式
在传统架构模式中,前后端代码存放于同一个代码库中,甚至是同一工程目录下。页面中还夹杂着后端代码。前后端工程师进行开发时,都必须把整个项目导入到开发工具中。而前后端分离模式在代码组织形式上有以下两种:
半分离
前后端共用一个代码库,但是代码分别存放在两个工程中。后端不关心或很少 关心前端元素的输出情况,前端不能独立进行开发和测试,项目中缺乏前后端 交互的测试用例。
真分离
前后端代码库分离,前端代码中有可以进行Mock测试(通过构造虚拟测试对 象以简化测试环境的方法)的伪后端,能支持前端的独立开发和测试。而后端 代码中除了功能实现外,还有着详细的测试用例,以保证API的可用性,降低 集成风险。
3.3.前后端分离开发模式
3.3.1.真正前后端分离
能力要求高,大公司
3.3.2.后端先行
能力要求低,小公司,刚转型前后端分离的公司
前后端分离全栈项目
3.4.前后端分离优缺点
优点:
分工明确,专业的人做专业的事情。
专业可以做出炫丽优美界面
人员培养更加专业化,精确化
缺点:
成本提高,人员多。
项目管理难度也提高,前后端都要管,协调他们之间交流。
它是趋势,移动互联要求必须有移动端,需要专业前端人员,好多公司都做前后端分离。
4.后端项目搭建
4.1.项目规划
项目 | 端口规划 |
---|---|
后台接口服务 | 8080 |
后台管理前端 | 8081 |
门户网站前端 | 80 |
所有的人都不能用cn.itsource的包名,org/cn.姓名英文
4.2.Idea配置maven
4.3.整合springboot环境
1)创建maven项目-用自己的包名
2)Pom 配置父亲
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
3)application.yml
server:
port: 8080
4)入口类
package cn.itsource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class PetHomeApplication {
public static void main(String[] args) {
SpringApplication.run(PetHomeApplication.class,args);
}
}
5)启动测试
启动测试
4.4.Ssm Crud
Pom.xml 配置文件 入口列 domain maper.java mapper.xml service/impl test controller
4.4.1.pom.xml
<!-- spring-boot整合mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
4.4.2.配置文件
application.yml
server:
port: 8081
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 0731javaroot
url: jdbc:mysql://localhost:3306/pethome?useUnicode=true&characterEncoding=UTF-8
mybatis:
type-aliases-package: cn.itsource.org.domain,cn.itsource.org.query,
准备库和表
入口类打扫描Mapper的标签
@MapperScan(“cn.itsource.*.mapper”)
4.4.3.创建部门domain
public class Department {
/*主键*/
private Long id;
/*部门编号*/
private String sn;
/*部门名称*/
private String name;
/*暂时不用*/
private String dirPath;
/*部门状态 0 正常 ,-1 停用*/
private int state;
/*部门经理 和员工关联*/
//private String manager;
/*上级部门
private Department parent;
private List<Department> children = new ArrayList<>();
*/
}
4.4.4. Lombok
在开发中每个类都需要写getter与setter方法,以及覆写toString。Lombok插件可以让开发中省略这部分重复的工作。
4.4.4.1. 引入相关jar包
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok
导入这个jar后,编译后会自动生成相关方法
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
4.4.4.2.IDEA添加插件对于Lombok的支持-编码时也支持
安装完成以后需要重启idea。
4.4.4.3.常用注解
官方文档:https://projectlombok.org/features/all
其中@Data注解最常用,标注于类之上,是@ToString,@EqualsAndHashCode、@Getter、@Setter、@RequiredArgsConstructor的综合体。
4.4.5.Mapper接口
public interface DepartmentMapper {
//基础查询
void save(Department d);
void remove(Long id);
void update(Department d);
Department loadById(Long id );
List<Department> loadAll();
/**
* 分页查询
*
*/
//查询总条数
Long queryCount(DepartmentQuery query);
//查询当前的页数
List<Department> queryData(DepartmentQuery query);
}
注意:DepartmentQuery 为Department的查询查询类,其中包括分页数据,以及关键字查询。
4.4.6.DepartmentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itsource.org.mapper.DepartmentMapper">
<!--//保存对象-->
<!--void save(Department department);-->
<insert id="save" parameterType="Department">
insert into t_department(
sn,
name,
dirPath,
state,
manager_id,
parent_id
)values(
#{sn},
#{name},
#{dirPath},
#{state},
#{manager.id},
#{parent.id}
)
</insert>
<!--//移除一个对象-->
<!--void remove(Long id);-->
<delete id="remove" parameterType="long">
delete from t_department where id = #{id}
</delete>
<!--//更新一个对象-->
<!--void update(Department department);-->
<update id="update" parameterType="Department">
update t_department set
sn=#{sn},
name=#{name},
dirPath=#{dirPath},
state=#{state},
manager_id=#{manager.id},
parent_id=#{parent.id}
where id = #{id}
</update>
<!--//加载一个对象-->
<!--Department loadById(Long id);-->
<select id="loadById" parameterType="long" resultType="Department">
select * from t_department where id = #{id}
</select>
<!--//加载所有对象-->
<!--List<Department> loadAll();-->
<select id="loadAll" resultType="Department">
select * from t_department
</select>
<!--//分页相关的,查询总数,查询当前页数据-->
<!--Long queryCount(DepartmentQuery query);-->
<select id="queryCount" parameterType="DepartmentQuery" resultType="long">
select count(*) from t_department
</select>
<!--List<Department> queryData(DepartmentQuery query);-->
<select id="queryData" parameterType="DepartmentQuery" resultType="Department">
select * from t_department
limit #{start},#{pageSize}
</select>
</mapper>
4.4.7.Service
public interface IDepartmentService {
void add(Department d);
void upadte(Department d);
void del(Long id );
Department getById(Long id );
List<Department> getAll();
/*
分页查询
*/
PageList<Department> queryData(DepartmentQuery query);
}
PageList 页面返回的数据:
/**
* 分页以后给页面返回的数据
* @param <T>
*/
public class PageList<T> {
//总条数
private Long tatal=0L;
//页面展示的数据
private List<T> rows = new ArrayList<>();
public PageList() {
}
public PageList(Long tatal, List<T> rows) {
this.tatal = tatal;
this.rows = rows;
}
}
实现类代码:
@Service
//类级别事务为读事务,分别在增删改的方法上面加写事务
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class DepartmentServiceImpl implements IDepartmentService {
@Autowired
private DepartmentMapper departmentMapper;
@Override
@Transactional
public void add(Department d) {
departmentMapper.save(d);
}
@Override
@Transactional
public void upadte(Department d) {
departmentMapper.update(d);
}
@Override
@Transactional
public void del(Long id) {
departmentMapper.remove(id);
}
@Override
public Department getById(Long id) {
return departmentMapper.loadById(id);
}
@Override
public List<Department> getAll() {
return departmentMapper.loadAll();
}
@Override
public PageList<Department> queryData(DepartmentQuery query) {
Long total = departmentMapper.queryCount(query);
if (total==null || total.intValue()<1){
return new PageList<>();
}
List<Department> list = departmentMapper.queryData(query);
return new PageList<>(total,list);
}
}
4.4.8.测试
4.4.9.Controller
见4.5
4.5.Controller
4.5.1.什么是Restful风格
Restful是一种面向资源的架构风格,可以简单理解为:使用URL定位资源,用HTTP动词(GET,POST,DELETE,PUT,PATCH(批量操作))描述操作。
get http://127.0.0.1:8080/user/1 获取用户
delete http://127.0.0.1:8080/user/1 删除用户
put http://127.0.0.1:8080/user/ 修改用户
{
Id:1
Name:zs
}
Post http://127.0.0.1:8080/user/ 添加用户
{
Name:zs
}
4.5.2.Restful好处
- 拥有http的优点
本身就是http,无状态,不用关心两次访问上下文. - 透明性,暴露资源存在
看到命令就知道要做什么了 - 充分利用 HTTP 协议本身语义。
原来只用get,post,现在连delete和put
4.5.3.特征
-
资源使用名词表示
资源是通过url描述,也就是在url不要出现动词 -
使用http动词来描述操作
get 获取 post新增 put修改 delete删除 patch批量操作json:数据传输方式之一
对象:{}
数组:[{},{}]
4.5.4.Controller实现
@GetMapping("xx")
@PostMapping("xx")
@DeleteMapping
@PutMapping
@RequestMapping(value = "xx",method = RequestMethod.POST)
package cn.itsource.org.controller;
import cn.itsource.basic.util.AjaxResult;
import cn.itsource.basic.util.PageList;
import cn.itsource.org.domain.Department;
import cn.itsource.org.query.DepartmentQuery;
import cn.itsource.org.service.IDepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController //@Controller+@ResponseBody(转换json)
@RequestMapping("/department")
public class DepartmentController {
@Autowired
private IDepartmentService departmentService;
//传对象就用@RequestBody
@PutMapping //添加或修改
public AjaxResult addOrUpdate(@RequestBody Department department) {
try {
if (department.getId() != null) {
departmentService.update(department);
} else {
departmentService.add(department);
}
return AjaxResult.me();
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.me().setSuccess(false).setMessage("保存失败!" + e.getMessage());
}
}
@DeleteMapping("/{id}") // /department/1
public AjaxResult delete(@PathVariable("id") Long id) {
try {
departmentService.delete(id);
return AjaxResult.me();
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.me().setSuccess(false).setMessage("删除失败!" + e.getMessage());
}
}
@GetMapping("/{id}")
public Department get(@PathVariable("id") Long id){
return departmentService.getById(id);
}
@GetMapping
public List<Department> getAll(){
return departmentService.getAll();
}
//axios get不支持传对象
@PostMapping
public PageList<Department> list(@RequestBody DepartmentQuery query){
return departmentService.queryPage(query);
}
}
AjaxResult :前台调用返回的数据
**
* 有些controller的操作以后的返回,只关心成功与否,以及失败了的原因
* 而且应该返回值是json数据。 {success:true/false,message:"系统错误“,resultObj:{}}
* 方案1; 后台拼接字符串返回 太麻烦,代码可读性差
* 方案2: 其实可以使用spirngmvc的自动转换json的功能
* 第一步:封装对象
* 封装一个对象,里面有两个属性 success ,message
* 到时候我构造一个对象返回,spirngmvc会自动帮我转换。
* 第二步:默认构造函数
*
* //成功的时候调用
public AjaxResult() {
}
//失败的时候调用
public AjaxResult(String message) {
this.success = false;
this.message = message;
//第三步:配置链式编程
//第四步:除了成功与否,还需要带一些额外数据到前台
}
*/
@Data
public class AjaxResult {
private boolean success = true;
private String message = "操作成功!";
private Object resultObj;
private Serializable sessionId;
public boolean isSuccess() {
return success;
}
//链式编程,可以继续. 设置完成后自己对象返回
public AjaxResult setSuccess(boolean success) {
this.success = success;
return this;
}
public AjaxResult setResultObj(Object resultObj){
this.resultObj = resultObj;
return this;
}
public String getMessage() {
return message;
}
public AjaxResult setMessage(String message) {
this.message = message;
return this;
}
//默认成功
public AjaxResult() {
}
//失败调用
public AjaxResult(String message) {
this.success = false;
this.message = message;
}
//不要让我创建太多对象
public static AjaxResult me(){
return new AjaxResult();
}
public static void main(String[] args) {
AjaxResult.me().setMessage("xxx").setSuccess(false);
}
}
如果是get请求还可以通过浏览器测试,但是其他请求就不行了。
4.6.Postman接口测试
我们基于springmvc写的controller对于前端来说就是接口,而且都是通过http协议访问,那后台写完后怎么测试呢?浏览器,只支持get。 要使用一些能够发送http各种请求的工具,其中postman就是很重要的一个。
4.6.1.什么是postman
就是一个工具,可以来发送各种http请求,可以用它来测试http协议接口.
postman就是httm协议接口测试工具
4.6.2.入门
4.6.2.1.下载安装
略过
4.6.2.2.注册和登录
略过
64009120@qq.com / hmtest123/hmtest123
4.6.2.3.测试crud接口
查询所有
添加
删除
略过
修改
4.7.接口规范swagger
4.7.1.为什么需要
1)接口测试人员要通过接口描述测试接口 --黑盒测试
2)前端开发人员要通过接口描述使用接口.
测试 怎么测试接口
前端人员 后端人员
怎么描述???
1)写接口doc文档
直接罗列所有接口,每个接口有访问地址(访问方式),参数及返回值.
2)可以直接通过后端代码产生能够让前台开发或测试人员能够看懂就ok—swagger文档 json,yml,页面展示 采纳
4.7.2.实现
添加swagger的jar包:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
添加配置类:
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//对外暴露服务的包,以controller的方式暴露,所以就是controller的包.
.apis(RequestHandlerSelectors.basePackage("cn.itsource"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("系统中心api")
.description("系统中心服务接口文档说明")
.contact(new Contact("hmtest", "", "hm@itsource.cn"))
.version("1.0")
.build();
}
}
4.7.3.访问接口规范
地址:http://localhost:8080/swagger-ui.html
@RestController //@Controller+@ResponseBody(转换json)
@RequestMapping("/department")
@Api(tags = "部门接口",description = "部门接口详细描述")
public class DepartmentController {
@Autowired
private IDepartmentService departmentService;
@ApiOperation(value = "部门添加或修改",notes = "如果有id就是修改否则就是添加")
//传对象就用@RequestBody
@PutMapping //添加或修改
4.8.小结
按照restfull规范写一个一个crud接口,通过postman来做接口测试,通过swagger来描述接口.
5.课程总结
5.1.重点
1.Mybatis的基本CRUD
2.Restful风格
5.2.难点
1.抽取
5.3.如何掌握
5.4.排错技巧(技巧)
6.常见问题
7.课后练习
1.完成当日代码