【Java开发实战】SpringBoot框架开发实用方法总结

大家好!我是,就是那个“请你跟我这样做,我就跟你这样做!”的村长?????!

||To Do||???

正推出一系列【To Do】文章,该系列文章重要是对Java开发方法的整理,便于在开发项目过程中及时回顾,提升个人开发实践能力。主要面向Java开发,总结常用的框架或中间件的使用方法。

文章目录

一、开发工具或技巧??

1、Lombok

“Never write another getter or equals method again, with one annotation.”

Lombok是一个Java库,可以通过注解的方式添加构造器、getter、setter或equals方法,提升开发人员的工作效率。

(1)添加依赖和插件

使用Lombok需要添加相应的依赖,除此还需要在IDEA中的Plugins搜索lombok插件进行安装。

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.4</version>
	<scope>provided</scope>
</dependency>

(2)常用注解

注解

说明

@Data

注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法

@AllArgsConstructor

注解在类,生成包含类中所有字段的构造方法。

@NoArgsConstructor

注解在类,生成无参的构造方法。

@EqualsAndHashCode

注解在类,生成hashCode和equals方法。

@Setter

注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。

@Getter

使用方法同上,区别在于生成的是getter方法。

@ToString

注解在类,添加toString方法。

@Slf4j

注解在类,生成log变量,严格意义来说是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);

(3)工作原理

Java注解的解析分为两种方式,一是运行时解析,二是编译时解析。

Lombok注解使用的是编译时解析:

  • 在javac之后,针对源代码会生成一个AST语法树,此时会启动Lombok进程对AST树进行修改
  • 找到对应的地方增加getter、setter方法的相应节点,根据该树生成新的字节码文件。

2、dev-tools

基于springboot进行开发,开发过程中,如果每次修改代码都将项目重启,将耗费大量的时间成本。

使用spring-boot-devtools,可以实现指定目录(默认为classpath路径)下的文件进行更改后,项目自动重启,更改后的代码自动生效。

重启快捷键:Ctrl + F9

(1)添加依赖和配置

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-devtools</artifactId>
   <optional>true</optional>
</dependency>

devtools依赖此配置,否则不生效。

<plugin>           		   		          			    <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-maven-plugin</artifactId>
   <configuration>
     <fork>true</fork>
   </configuration>
</plugin>

(2)原理

spring-boot-devtools使用了两个类加载器ClassLoader,一个ClassLoader加载不会发生更改的类(第三方jar包),另一个ClassLoader(restart ClassLoader)加载已更改的类(自定义的类)。

依旧是重启应用,但是第三方jar包不会进行再次加载,只会加载我们自定义的且被修改的类,加载的类变少则减少了重启加载时间。

3、API测试—Apifox

百度搜索Apifox进行下载,下载完成后应用类就有相应的教程。官方对Apifor定位,Apifox = Postman + Swagger + Mock + JMeter,即对现有Api调试产品的集成。

相关使用文档:接口调试 / 接口用例 | Apifox 使用文档

在这里插入图片描述

该应用对标Postman,提供了更细致的Api测试服务(Apifox打钱!!!)。

在这里插入图片描述

4、配置文件

(1)yaml格式配置文件

YAML(YAML Ain’t Markup Language)以数据为中心,比json、xml更适合做配置文件。

YAML都是key: value配置,:后必须有空格,换行可代替空格进行嵌套配置,以左对齐为属性的附属设置。

# 这是一个注解

#1、对象或Map
friend:
	name: zhangsan
	age: 20
#行内写法
friend: {name:zhangsan,age:20}

#2、数组、List或Set
pets:
 - cat
 - dog
 - pig
#行内写法
pets: [cat,dog,pig]

(2)配置文件属性绑定

我们可以通过注解类的方式,将配置文件的内容注入到相应的Bean中。当Bean被实例化时,@ConfigurationProperties会将对应前缀的后面的属性与Bean对象的属性匹配。符合条件则进行赋值。

@ConfigurationProperties(prefix="属性名")

(3)配置提示工具

Configuration-Processor是用于配置文件时使用的配置提示工具,可在编码时进行Coding提示。需要添加依赖如下。

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-configuration-processor</artifactId>
   <optional>true</optional>
</dependency>

这个Java库只用于代码编写时进行提示,我们打包SpringBoot应用时不需要将其打包,则需要添加以下Maven插件配置,这样在项目打包时就不会将spring-boot-configuration-processor中的类进行打包。

<plugin>           		   		          			    <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-maven-plugin</artifactId>
   <configuration>
     <execuldes>
         <execulde>
			<groupId>org.springframework.boot</groupId>
   			<artifactId>spring-boot-configuration-processor</artifactId>
         <execulde>
     <execuldes>
   </configuration>
</plugin>

二、请求与响应??

1、调用层级与注解

(1)调用层级

SpringBoot开发我们通常分为Dao、Service、Controller、Entity四个层级。

  • Dao:编写与数据库交互相应接口(一般结合Mybatis)。
  • Service:编写业务处理逻辑,一般先写接口,再通过实现impl类进行代码的编写。
  • Controller:编写请求处理与响应返回逻辑。
  • Entity:实体类,用于建立系统程序的实体对应POJO类(对应数据库的相关表段)或对请求响应相关数据的封装。

(2)相关注解

@Controller、@Repository、@Service、@Component四大注解可代表不同的层级,其中@Controller、@Repository、@Service都是@Component注解的衍生注解。在启动类中配置的ComponentScan

  • @Controller:注解控制器类
  • @Repository:注解Dao类或接口
  • @Service::注解Service类或接口
  • @Component:注解普通类

2、请求接收

(1)普通类型参数

当请求路径url附带的key-value值的参数名称与请求参数的名称一致时,会自动映射匹配。

http://localhost:8080/arg?username=chief&age=18


@RequestMapping(value = "arg")
public void sout(String username, int age) {
    System.out.println(username);
    System.out.println(age);
}

(2)POJO类型

Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。

http://localhost:8080/arg?username=chief&age=18


@Data
public class User {
	private String username;
	private int age;
}

@RequestMapping(value = "/arg")
public void sout(User user) {
    System.out.println(user);
}

(3)数组类型参数

Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。

http://localhost:8080/arg?strs=1&strs=2&strs=3


@RequestMapping(value = "/arg")
public void sout(String[] strs) {
    System.out.println(Arrays.asList(strs));
}

(4)集合类型参数

获得集合参数时,要将集合参数包装到一个POJO中才可以,即当通过浏览器提交form表单时。

<form action="${pageContext.request.contextPath}/arg" method="post">
    <input type="text" name = "username"><br/>
    <input type="text" name = "age"><br/>
    <input type="submit" value="提交">
</form>


@Data
public class UserVo {
	private String username;
	private int age;
}

@RequestMapping(value = "/arg")
public void sout(UserVo vo) {
    System.out.println(vo);
}

(5)相关注解的使用

① RequestBody

@RequestBody主要用来接收前端传递给后端的json字符串数据,接收的参数是来自请求体,@RequestBody最多只能有一个。不能用于GET请求,因为GET请求没有请求体。

会根据json字符串中的key来匹配对应@RequestBody实体类的属性,@RequestBody的作用就是自动将json格式的数据转java对象。

$.ajax({
   url:"/arg",
   type:“POST”,
   data:’{“username”:“admin”,“age”,“18”}’,
   content-type:“application/json charset=utf-8”,
   success:function(data){
   		alert("request success !");
   }
});


@requestMapping("/arg")
public void sout(@requestBody User user){
	System.out.println(user);
}
② RequestParam

RequestParam作用是将请求参数绑定到对应Controller的方法参数上,用于接收普通请求参数,可以是url请求,也可以是请求体中的参数。

不加RequestParam也能接收url后的参数,如果不加@RequestParam,则url请求可以带参数也可以不带,如果加了该注解则必须带参数【可设置required为false,这样也可以不带参数】。

@RequestParam(value="参数名",required="true/false",defaultValue="")
//- value:参数名
//- required:是否包含该参数,默认为true
//- defaultValue:默认参数值,设置以后required设置为false


http://localhost:8080/arg?name=chief


@RequestMapping("/arg")
public void sout(@RequestParam("name") String name){
    System.out.println(name);
}
③ PathVariable

作用也是接收普通参数,区别是@PathVariable通过"/"的方式来获取参数值,即实现RESTful风格,现在开发常用PathVariable代替RequestParam。

@RequestMapping("/arg/{name}")
public void sout(@PathVariable("name") String name){
    System.out.println(name);
}
④ RequestAttribute

作用是从request请求中取对应的属性值。

@GetMapping("/arg")
public void sout(@RequestAttribute("requestArg") String name) {
        System.out.println(name);
}

等同于:

request.getAttribute("name"); 

(6)通过HttpServletRequest

HttpServletRequest可用于获取用户提交的表单数据,相关方法如下:

方法

说明

String getParameter(String name)

该方法用于获取某个指定名称的参数值,如果请求消息中没有包含指定名称的参数,getParameter()方法返回null;如果指定名称的参数存在但没有设置值,则返回一个空串;如果请求消息中包含有多个该指定名称的参数,getParameter()方法返回第一个出现的参数值

String[] getParameterValues(String name)

HTTP请求消息中可以有多个相同名称的参数(通常由一个包含有多个同名的字段元素的FORM表单生成),如果要获得HTTP请求消息中的同一个参数名所对应的所有参数值,那么就应该使用getParameterValues()方法,该方法用于返回一个String类型的数组

Map getParameterMap()

用于将请求消息中的所有参数名和值装入进一个Map对象中返回

<form action="/login" method="post">
 	 	用户名:<input type="text" name="username">
    	密码:<input type="password" name="password">
 	 	<input type="submit" value="提交">
</form>


@RequestMapping("/login")
public void login(HttpServletRequest request){
    String username = request.getParameter("username");
    String password = request.getParameter("password");
}

3、Cookie与Session

(1)自定义Cookie

我们以登录为例。

<form action="login" method="post">
	用户:<input type="text" name="username" /><br/>
	密码:<input type="text" name="password" /><br/>
	<input type="submit" value="登录">
</form>

在自定义Cookie时,我们需要使用HttpServletResponse对象,将其加入到HttpServletResponse,作为响应返回的一部分。

@RequestMapping("/login")
public void login(String username, String password, HttpServletResponse response) {
		System.out.println(username+":"+password );
		//创建cookie信息,在构造函数中设置名字和值,第一个参数是名字,第二个参数是值。
		Cookie userCookie = new Cookie("username", username);
		Cookie pwdCookie = new Cookie("password", password);
		//将cookie信息放到回应response中
		response.addCookie(userCookie);
		response.addCookie(pwdCookie);
}

加入到HttpServletResponse后可在服务端Controller任意方法中进行获取,在SpringMVC中使用注解@CookieValue获取
注解中name为cookie的名字,required设置为false。

@RequestMapping(value="/student", method = RequestMethod.GET)
public void get(@CookieValue(name = "JSESSIONID", required = false)String jid, @CookieValue(name = "username", required = false)String username, @CookieValue(name = "password", required = false)String password) {
		System.out.println("session id 是:" + jid);
		System.out.println("当前登录用户名为:" + username + ",密码为: " + password );
}

(2)Session的使用

由于cookie的数量有限制,安全性也较低,为了满足更多需求,可以使用session。当服务器创建完session对象后,会把session对象的id以cookie形式返回给客户端。session是在第一次访问网站时创建出来的,我们使用时不需要再创建。Session的获取有以下两种方式

//方式一
public void get(HttpServletRequest request){
 HttpSession session = request.getSession();
}
//方式二
public void get(HttpSession session){
}

Session提供了以下方法对其进行操作。

public void setAttribute(String name,Object value)
//将value对象以name名称绑定到会话
public object getAttribute(String name)
//获取指定name的属性值,如果属性不存在则返回null
public void removeAttribute(String name)
//从会话中删除name属性,如果不存在不会执行,也不会抛处错误
public Enumeration getAttributeNames()
//返回和会话有关的枚举值
public void invalidate()
//使会话失效,同时删除属性对象
public Boolean isNew()
//用于检测当前客户是否为新的会话
public long getCreationTime()
//返回会话创建时间
public long getLastAccessedTime()
//返回在会话时间内web容器接收到客户最后发出的请求的时间
public int getMaxInactiveInterval()
//返回在会话期间内客户请求的最长时间.秒
public void setMasInactiveInterval(int seconds)
//允许客户客户请求的最长时间
ServletContext getServletContext()
//返回当前会话的上下文环境,ServletContext对象可以使Servlet与web容器进行通信
public String getId()
//返回会话期间的识别号

4、响应方式

(1)统一封装返回json对象[建议]

在SpringBoot实际开放中,我们需要通过定义统一的响应对象,以便前端处理。SpringBoot框架默认添加了Jackson依赖,我们只需要通过@ResponseBody或@RestController说明返回的值为对象即可。

通常我们将需要返回的对象封装为以下形式,code表示响应码,info表示响应信息,data表示我们需要传入的对象数据。

@Data
public class Response<T> {
    private Integer code;
    private String info;
    private T data;
}

在返回响应值时,我们只需要将属性封装到一个对象中进行返回即可。

(2)返回ModelAndView

返回ModelAndView,即将返回的数据和界面名称都给ModelAndView。

@RequestMapping(value="/login")
public ModelAndView WelcomeSeven(){
    //创建ModelAndView对象
    ModelAndView mav = new ModelAndView("index");
    mav.addObject("name", "张三");
    mav.addObject("role", "管理员");
    return mav;
}


@RequestMapping(value="/login")
public String WelcomeEight(Model model){
    model.addAttribute("name", "张三");
    model.addAttribute("role", "管理员");
    return "index";
}

(3)返回String

直接返回字符串的话,返回的是界面的名称。

(4)通过Map对象返回

@RequestMapping(value="/login")
public String WelcomeNine(Map<String,String> map){
    map.put("name", "张三");
    map.put("role", "管理员");
    return "index";
}

(5)通过Request域返回

@RequestMapping("/login")
public String index(HttpServletRequest request){
    request.setAttribute("name", "张三");
    request.setAttribute("role", "管理员");
    return "index";
}

5、重定向方式

(1)通过String

@GetMapping(value = "test")
public String test(){
    return "redirect:https://www.baidu.com";
}

(2)通过ModelAndView

@GetMapping(value = "test")
public ModelAndView test(){
    return new ModelAndView("redirect:https://www.baidu.com");

}

6、SpringMVC请求处理原理

SpringMVC的请求处理过程的时序图【图源网络】:

在这里插入图片描述

DispacherServlet会先进行初始化,初始化过程分为两步,一是初始化WebApplicationContext容器,然后再初始化HandlerMapping、HandlerAdapter、ViewResolver等Web组件。

对于请求的处理分为以下步骤:

  • DispatcherServlet通过doService调用doDispatch,对容器封装的Request和Response进行处理。[doDispatch(request,reponse)]

  • 通过getHandler获取到HandlerExecutionChina对象mappedHandler[HandlerExecutonChina mappedHandler = getHandler(processedRequest)]

    • getHandler方法通过遍历HandlerMapping,找到对应映射关系的handler并进行返回
  • handlerExecutorChina 执行链对象获取到对应的handlerAdapter,handler适配器[handlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler())]

  • 根据适配器真正执行handler ,并且返回一个modeAndView,在执行该方法前后会通过preHandler和postHandler执行相关的拦截方法。[mv=ha.handler(xxx)]

  • 最后通过获取的ModelAndView,解析渲染页面并返回结果[processDispatchResult(processedRequest,response,mappedHAndler,mv,dispatchException)]

    • process方法通过render()完成页面的渲染

三、文件上传??

1、文件上传例子

浏览器文件通过表单进行上传。

<form method:"post" enctype="multipart/form-data">
	<input type="file" name="img"> 单文件上传
	<input type="file" name="imgs" multiple> 多文件上传
    <button type="submit">提交</button>
<form/>

对应编写的Controller如下。

@PostMapping("/upload")
public void upload(
    @RequestParam("img") MutipartFile file,
	@RequestParam("imgs") MutipartFile[] files){
    if(!file.isEmpty()){
    	file.transferTo(new File("文件存放路径\"+"文件名"))
    }
    
    if(files.length>0){
        for(MutipartFile f : files){
            if(!f.isEmpty()){
    		f.transferTo(new File("文件存放路径\"+"文件名"))
    }
}

2、文件上传配置

SpringBoot默认设置了文件上传的参数,其中最大文件上传大小默认为1M,一次请求上传的文件大小不超过10M,我们可以通过修改配置文件来修改相关设定。

# 开启multipart上传功能
spring.servlet.multipart.enabled=true
# 文件写入磁盘的阈值
spring.servlet.multipart.file-size-threshold=2KB
# 最大文件大小
spring.servlet.multipart.max-file-size=200MB
# 最大请求大小
spring.servlet.multipart.max-request-size=215MB
# 文件存储所需参数
# 所有通过 REST API 上传的文件都将存储在此目录下
file.upload.path=文件上传路径

四、拦截器??

配置拦截器可分为两个步骤:自定义拦截器器和配置拦截器。

1、自定义配置器

自定义配置器需要我们实现HandlerInterceptor接口,一般只需要拦截Controller方法执行前的操作即可。

@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("controller执行前");
        return true;//true表示放行
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		System.out.println("渲染前-controller执行后");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
		System.out.println("渲染后处理");
    }
}

2、配置拦截器

我们通过配置类的编写来进行具体配置,这个类不仅配置了相应的类,并且

@Configuration//定义此类为配置类
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    	//addPathPatterns拦截的路径
        String[] addPathPatterns = {
                "/path/**"
        };
        //excludePathPatterns排除的路径
        String[] excludePathPatterns = {
                "/path/xxx1","/path/xxx2"
        };
        //添加自定义拦截器对象并指定其拦截的路径和排除的路径
        registry.addInterceptor(new MyInterceptor()).addPathPatterns(addPathPatterns).excludePathPatterns(excludePathPatterns);
    }
}

也可以写在一行:

@Override
public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(new MyInterceptor()).addPathPatterns("/path/**").excludePathPatterns("/path/xxx1","/path/xxx2");
}

3、实现例子—登录拦截

(1)拦截器

public class UserInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //从session中获取user的信息
        User user =(User)request.getSession().getAttribute("user");
        //判断用户是否登录
        if (null==user){
            //重定向
            response.sendRedirect(request.getContextPath()+"/user/error");
            //不放行
            return false;
        }
        return true;
    }
}

(2)拦截器配置类

@Configuration//定义此类为配置类
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    	//addPathPatterns拦截的路径
        String[] addPathPatterns = {
                "/user/**"
        };
        //excludePathPatterns排除的路径
        String[] excludePathPatterns = {
                "/user/login","/user/noLg","/user/error"
        };
        //创建用户拦截器对象并指定其拦截的路径和排除的路径
        registry.addInterceptor(new UserInterceptor()).addPathPatterns(addPathPatterns).excludePathPatterns(excludePathPatterns);
    }
}

五、事务??

1、事务开启方式

(1)在启动类上开启事务支持

@EnableTransactionManagement

该注解代替了以下xml配置:

<!--事务的注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

(2)在业务逻辑接口实现类声明事务

@Transactional(propagation=Propagation.REQUIRED,readOnly=false)
public void tranSerciveImpl(){}

2、事务补充说明

(1)提示

Transactional注解只能应用到public方法上,@Transactional注解的事物所管理的方法中,如果方法抛出运行时异常,那么会进行事务回滚;如果方法抛出的是非运行时异常,那么不会回滚。

我们可以通过更改rollbackFor = {Exception.class} 设置当Exception异常或Exception的所有任意子类异常时事物会进行回滚,且被catch处理了的异常,不会被事务作为回滚判断依据。

(2)事务处理原理

Spring事务处理主要依靠以下几个核心类:

  • TransactionInterceptor:使用AOP实现的声明式事务处理拦截器,封装了Spring对事务处理的基本过程。
  • TransactionInfo和TransactionStatus:存放事务处理信息的主要数据对象,TransactionInfo持有TransactionStatus对象。
    • TransactionInfo本身是一个栈,对应着每一次事务方法的调用时保存的事务处理信息
    • TransactionStatus掌管事务执行的详细信息,包括事务对象、事务执行状态、事务设置状态等信息
  • TransactionManager:具体进行事务处理的事务处理器,负责最底层事务的创建、挂起、提交、回滚操作。
    • DataSourceTransactionManager:AbstractPlatformTransactionManager的子类,AbstractPlatformTransactionManager已经设计好了事务创建、挂起、提交、回滚操作的模板方法。DataSourceTransactionManager通过doBegin方法创建事务,该方法会得到相应的Connection对象,事务的配置、提交、回滚都是通过直接调用Connection来完成。
    • HibernateTransactionManager在调用doBegin创建事务时,会打开一个Session,该类是Hibernate管理数据对象生命周期的核心类,HibernateTransactionManager通过对Session的管理来完成事务处理实现。

六、异常处理??

1、全局异常捕获

SpringBoot中提供了@ControllerAdvice@ExceptionHandler两个注解来实现专门对服务器500异常进行自定义处理。

定义一个类,使用 @ControllerAdvice 注解该类,使用 @ExceptionHandler 注解方法,定义了一个 GlobalExceptionHandler 类表示来处理全局异常,代码如下:

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
	@ExceptionHandler(value = {xxx1Exception.class,xxx2Exception.class})
	public String arithmeticExceptionHandle(Exception e) {
        log.error("捕获异常:"+e);
		return "error";//返回视图地址
	}
}

@ControllerAdvice注解表示我们定义的是一个控制器增强类,当其他任何控制器发生异常且异常类型符合@ExceptionHandler注解中指定的异常类时,原请求将会被拦截到这个我们自定义的控制器方法中。

2、自定义错误页

SpringBoot默认的错误处理机制可以自动返回相应的错误信息(以json或页面的形式),我们也可以自定义错误页面。只需要将该页面放在resource/public/error/或resource/templates/error下

页面名称为相应的响应码,例如404,400等。响应码可以定义为4xx,5xx,xx相当于通配符,可以返回以4开头或5开头的错误页面。

——————————————————————

作者:

参考:文章出于整理目的出发,参考了多篇博文,侵删

个人网站:www.76pl.com

???还有人不关注我的话,我真的会谢???

——————————————————————

猜你喜欢

转载自blog.csdn.net/m0_67401660/article/details/125346944
今日推荐