SpringBoot+Spring+MyBatis相关知识点
目录
一、相关概念
1.spring框架
2.springcloud
3.SpringBoot项目
4.注解
5.SpringBoot的文件结构
6.启动类原理
二、相关操作
1.Jar方式打包
2.自定义返回的业务状态码
3.Jackson
4.加载配置文件
5.异常处理
三、优化配置
1.简化sql语句
2.查询操作
复杂查询
一对一联表查询
一对多联表查询
小结
一、相关概念
1.spring框架
也可称为DI,IoC,AOP框架,相当于是一个容器,每一个对象就是一个bean
对于项目构建过程:Controller -> Service -> Dao
未用框架时,需要实例化service实现类来调用方法
private UserService userService = new UserService();
使用Spring框架后,可通过注解来实现自动装配对象
@Autowire
private UserService userService
2.springcloud
是基于springboot, 只不过是在之前基础上多了几个插件包
3.SpringBoot项目
SpringBoot是一个通过注解简化配置的web开发框架。
有两种创建方式:
本地创建-先创建一个普通maven项目,再参考官方文档:Getting Started | Building an Application with Spring Boot
添加相关maven依赖;
在线创建 -https://start.spring.io/
开发JSON接口,可通过@RestController注解实现,可将要显示的数据序列化成JSON对象.
4.注解
本质是继承Annotation接口,起到说明、配置的作用
常见注解:
@Controller用于标记类是一个控制器,返回页面的时使用,但如果要返回JSON,需要再添加@ResponseBody
@RestController 用于标记类是一个控制器,并返回JSON数据,实现接口返回数据会被序列化为JSON,相当于@Controller+@ResponseBody
@RequestMapping 设置路由映射,为某个方法设置子路径
@GetMapping用于设置get请求查询接口的路径,相当于@RequestMapping(method = RequestMethod.GET)
同理有
@PostMapping = @RequestMapping(method = RequestMethod.POST) @PutMapping = @RequestMapping(method = RequestMethod.PUT)
@DeleteMapping = @RequestMapping(method = RequestMethod.DELETE)
@SpringBootApplication 用于标记是SringBoot应用,里面包含多个子注解,相当于@Configuration(spring扫描注入)+@EnableAutoConfiguration(自动载入所需Bean)+@ComponentScan(spring扫描包的范围)
@Component标记这个是一个组件,相当于在启动类中添加@Bean,new一个对象
@Scheduled注解是一个定时任务注解,可以在方法上添加,表示这个方法是一个定时任务方法
5.SpringBoot的文件结构
- src/main/java:存放代码
- src/main/resources:存放静态资源
- static: 存放静态文件,比如 css、js、image, (访问方式 http://localhost:8080/js/main.js)
- templates:存放静态页面jsp,html,tpl
- config:存放配置文件,application.properties
静态文件加载顺序
META/resources ----->resources -------->static ------->public
6.启动类原理
启动类和controller分开存放,启动类要放在根目录下,在启动类上只需要注解@SpringBootApplication
二、相关操作
1.Jar方式打包
只需在pom.xml文件中添加插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
如果没有加,则执行jar包 ,报错如下 java -jar spring-boot-demo-0.0.1-SNAPSHOT.jar no main manifest attribute, in spring-boot-demo-0.0.1-SNAPSHOT.jar
打包与启动命令
- 构建:mvn install
target目录下的jar包就是打包后项目
- 进到对应的target
- 目录启动 java -jar xxxxx.jar
- 保持后台运行,守护进程 nohup java -jar xxx.jar &(但windows下没有,只能在linux或mac下运行实现)
2.自定义返回的业务状态码
在utils包下添加JSONData工具类实现
package net.xdclass.demoproject.utils;
/**
* 接口返回工具类
*/
public class JsonData {
private int code;
private Object data;
private String msg;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public JsonData(){}
public JsonData(int code, Object data){
this.code = code;
this.data = data;
}
public JsonData(int code, Object data, String msg){
this.code = code;
this.data =data;
this.msg = msg;
}
public static JsonData buildSuccess(Object data){
return new JsonData(0,data);
}
public static JsonData buildError(String msg){
return new JsonData(-1,"",msg);
}
public static JsonData buildError(String msg,int code){
return new JsonData(code,"",msg);
}
@Override
public String toString() {
return "JsonData{" +
"code=" + code +
", data=" + data +
", msg='" + msg + '\'' +
'}';
}
}
在controller层中直接调用即可
//将返回的list对象用工具类封装成json格式的字符串返回给前端
return JsonData.buildSuccess(video);
3.Jackson
jackson注解,处理相关自动
@JsonIgnore(指定字段不返回)、@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss",locale="zh",timezone="GMT+8")(指定日期格式)、@JsonInclude(Include.NON_NULL)(空字段不返回)、@JsonProperty(指定别名)
序列化和反序列化操作
//序列化操作 ObjectMapper objectMapper = new ObjectMapper(); String jsonStr = objectMapper.writeValueAsString(list); System.out.println(jsonStr); //反序列化操作 List<Video> temp = objectMapper.readValue(jsonStr,List.class);
4.加载配置文件
方式一
- Controller中通过注解指定资源路径(@PropertySource({"classpath:resource.properties"}))
- 增加属性@Value("${test.name}") private String name;
方式二:
创建一个实体类配置文件WXConfig
package net.xdclass.demoproject.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.io.Serializable;
@Configuration//表示这是一个配置类,用于加载配置文件中的属性值,会被Spring容器扫描
@PropertySource(value="classpath:pay.properties")
public class WXConfig implements Serializable {
@Value("${wxpay.appid}")//从配置文件中获取属性值,并赋值给payAppid
//或者@Value("${wxpay.appid}")
private String payAppid;
@Value("${wxpay.secret}")
private String paySecret;
@Value("${wxpay.mechid}")
private String payMechId;
public String getPayAppid() {
return payAppid;
}
public void setPayAppid(String payAppid) {
this.payAppid = payAppid;
}
public String getPaySecret() {
return paySecret;
}
public void setPaySecret(String paySecret) {
this.paySecret = paySecret;
}
public String getPayMechId() {
return payMechId;
}
public void setPayMechId(String payMechId) {
this.payMechId = payMechId;
}
}
在TestController中引入
package net.xdclass.demoproject.controller;
import net.xdclass.demoproject.config.WXConfig;
import net.xdclass.demoproject.task.AsyncTask;
import net.xdclass.demoproject.utils.JsonData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@RestController
@RequestMapping("api/v1/test")
@PropertySource({"classpath:pay.properties"})//在classpath目录下查找配置文件的路径
public class TestController {
@Value("${wxpay.appid}")//从配置文件中获取属性值,并赋值给payAppid
// @Value("${wxpay.appid}")//方式2
private String payAppid;
@Value("${wxpay.secret}")
private String paySecret;
@Autowired//会自动将WXConfig对象注入到TestController对象中
private WXConfig wxConfig;
@GetMapping("get_config")
public JsonData testConfig(){
Map<String,String> map = new HashMap<>();
// map.put("appid",payAppid);
// map.put("secret",paySecret);
//
// return JsonData.buildSuccess(map);
//通过配置类获取属性值,并封装成map对象返回给前端
map.put("appid",wxConfig.getPayAppid());
map.put("secret",wxConfig.getPaySecret());
map.put("mechid",wxConfig.getPayMechId());
return JsonData.buildSuccess(map);//将返回的map对象用工具类封装成json格式的字符串返回给前端
}
}
在postman中可通过接口来访问得到数据,来模拟客户端
5.异常处理
全局异常处理实现
创建一个全局异常处理类
类添加注解
@ControllerAdvice,如果需要返回json数据,则方法需要加@ResponseBody
@RestControllerAdvice, 默认返回json数据,方法不需要加@ResponseBody
方法添加处理器
@ExceptionHandler(value=Exception.class)
package net.xdclass.demoproject.handler;
import net.xdclass.demoproject.utils.JsonData;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
* 标记这个是一个异常处理类
*/
@RestControllerAdvice//标记这个是一个异常处理类,可以处理全局异常
public class CustomExtHandler {
//处理特定异常:Exception.class
@ExceptionHandler(value = Exception.class)//标记这个方法是一个异常处理方法,处理Exception.class异常
JsonData handlerException(Exception e, HttpServletRequest request){
//打印异常信息
return JsonData.buildError("服务端出问题了", -2);
}
}
自定义全局异常
引入thymeleaf依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
创建异常显示视图
resource目录下新建templates,并新建error.html
创建异常处理类
package net.xdclass.demoproject.handler;
import net.xdclass.demoproject.utils.JsonData;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
* 标记这个是一个异常处理类
*/
@ControllerAdvice//标记这个是一个异常处理类
public class CustomExtHandler {
@ExceptionHandler(value = Exception.class)
Object handlerException(Exception e, HttpServletRequest request){
//打印异常信息:ModelAndView:视图和模型的结合,可以将数据传递给视图,并渲染视图
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error.html");//设置视图名称:error.html,会自动去templates目录下查找error.html文件,并渲染
System.out.println(e.getMessage());//打印异常信息
//将异常信息传递给视图
modelAndView.addObject("msg",e.getMessage());
return modelAndView;
}
}
三、优化配置
1.简化sql语句
sql片段的使用:select * 去查询数据库不适用高并发项目
简化前
<select id="selectById" parameterType="java.lang.Integer" resultType="Video">
select id,title,summary,cover_img from video where id = # {video_id,jdbcType=INTEGER}
</select>
简化后
<sql id="base_video_field">
id,title,summary,cover_img
</sql>
<select id="selectById" parameterType="java.lang.Integer" resultType="Video">
select <include refid="base_video_field"/> from video where id = # {video_id,jdbcType=INTEGER}
</select>
2.查询操作
复杂查询
sql的两种返回类型:resultType(适用于简单查询)、resultMap(适用于复杂查询)
用resultMap来实现:在xml文件中配置
<!--1.配置映射结果集 2.编写查询语句实现查询-->
<resultMap id="VideoResultMap" type="Video">
<!--
id 指定查询列的唯一标示
column 数据库字段的名称
property pojo类的名称
-->
<id column="id" property="id" jdbcType="INTEGER" />
<result column="video_tile" property="title" jdbcType="VARCHAR" />
<result column="summary" property="summary" jdbcType="VARCHAR" />
<result column="cover_img" property="coverImg" jdbcType="VARCHAR" />
</resultMap>
<!--通过配置resultMap将as后面的数据库类型映射成as前面的java类型 -->
<select id="selectBaseFieldByIdWithResultMap" resultMap="VideoResultMap">
select id , title as video_title, summary, cover_img from video where id = #{video_id}
</select>
在Mapper接口中编写方法
//复杂查询
Video selectBaseFieldByIdWithResultMap(@Param("video_id")int id);
启动类中输出
//resultMap映射出来得到的结果
System.out.println(videoMapper.selectBaseFieldByIdWithResultMap(30));
一对一联表查询
当需要同时查询两个表的信息时,通过association来配置一对一的关联表属性。
xml文件中
<resultMap id="VideoOrderResultMap" type="VideoOrder">
<!--配置id为唯一标识-->
<id column="id" property="id"/>
<!--配置结果集映射-->
<result column="user_id" property="userId"/>
<result column="out_trade_no" property="outTradeNo"/>
<result column="create_time" property="createTime"/>
<result column="state" property="state"/>
<result column="total_fee" property="totalFee"/>
<result column="video_id" property="videoId"/>
<result column="video_title" property="videoTitle"/>
<result column="video_img" property="videoImg"/>
<!--配置关联表的映射属性:
association 配置属性一对一
property 对应videoOrder里面的user属性名
javaType 这个属性的类型
-->
<association property="user" javaType="User">
<id property="id" column="user_id"/>
<result property="name" column="name"/>
<result property="headImg" column="head_img"/>
<result property="createTime" column="create_time"/>
<result property="phone" column="phone"/>
</association>
</resultMap>
<!--一对一管理查询订单, 订单内部包含用户属性-->
<select id="queryVideoOrderList" resultMap="VideoOrderResultMap">
select
o.id id,
o.user_id ,
o.out_trade_no,
o.create_time,
o.state,
o.total_fee,
o.video_id,
o.video_title,
o.video_img,
u.name,
u.head_img,
u.create_time,
u.phone
from video_order o left join user u on o.user_id = u.id
</select>
mapper接口
package net.xdclass.online_class.dao;
import net.xdclass.online_class.domain.User;
import net.xdclass.online_class.domain.VideoOrder;
import java.util.List;
public interface VideoOrderMapper {
/**
* 查询全部订单,关联用户信息
* @return
*/
List<VideoOrder> queryVideoOrderList();
}
启动类中
// resultmap association关联查询
VideoOrderMapper videoOrderMapper = sqlSession.getMapper(VideoOrderMapper.class);//获取mapper对象
List<VideoOrder> videoOrderList = videoOrderMapper.queryVideoOrderList();//调用mapper接口中的方法
System.out.println(videoOrderList.toString());//输出结果
一对多联表查询
查询关联表信息中的返回多条数据,用collection来实现接收多条数据
<resultMap id="UserOrderResultMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="headImg" column="head_img"/>
<result property="createTime" column="create_time"/>
<result property="phone" column="phone"/>
<!--
property 填写pojo类中集合类属性的名称
ofType 集合里面的pojo对象
-->
<collection property="videoOrderList" ofType="VideoOrder">
<!--配置主键,管理order的唯一标识-->
<id column="order_id" property="id"/>
<result column="user_id" property="userId"/>
<result column="out_trade_no" property="outTradeNo"/>
<result column="create_time" property="createTime"/>
<result column="state" property="state"/>
<result column="total_fee" property="totalFee"/>
<result column="video_id" property="videoId"/>
<result column="video_title" property="videoTitle"/>
<result column="video_img" property="videoImg"/>
</collection>
</resultMap>
<select id="queryUserOrder" resultMap="UserOrderResultMap">
select
u.id,
u.name,
u.head_img,
u.create_time,
u.phone,
o.id order_id,
o.out_trade_no,
o.user_id,
o.create_time,
o.state,
o.total_fee,
o.video_id,
o.video_title,
o.video_img
from user u left join video_order o on u.id = o.user_id
</select>
小结