目录
一、相关概念
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);}@Overridepublic 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}")//方式2private 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">selecto.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.phonefrom 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">selectu.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_imgfrom user u left join video_order o on u.id = o.user_id</select>
小结