Springboot
-
2014年推出第一个版本,Springboot主要的目的是简化Spring框架开发的过程
-
开发理念是约定大于配置
-
优点
- 简化Spring框架开发环境的搭建
- 没有xml配置
- 通过stater的设计,简化了maven管理的依赖
- 简化了应用的部署,Springboot框架内部自己封装了tomcat、jetty等服务器
- 可以快速的构建和启动一个Web应用
-
Springboot项目的构建方式
- 在官网上通过quick start构建
- 直接创建一个maven项目进行构建,需要手动导入Springboot的依赖
-
以maven方式项目构建
-
引入基础核心依赖
<!--继承springboot的父项目--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> </parent> <dependencies> <!--引入springboot的web支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
-
Springboot项目的目录结构约定
-
目录结构
- com
- |-mo
- |-entity、dao、service、controller、启动类App:这个启动类启动时,会扫描同级位置包结构下的spring相关注解,同时还会启动springboot内部的tomcat,位置必须与dao、service、controller这些包同级,或者这些包的父目录上
- |-mo
- com
-
配置文件 —> application.properties / application.yml / application.yaml
-
配置文件位置要在项目的根目录下
//和二级目录在一块 app.java /** * 用注解声明当前类是一个启动类 */ @SpringBootApplication public class App { public static void main(String[] args) { //指定启动类,运行后会启动整个Web应用 SpringApplication.run(App.class,args); } } //配置文件根目录下 application.properties #指定springboot内置tomcat启动的端口号 server.port=8989 @RestController //相当于@Controller+@ResponseBody @RequestMapping("hello") public class HelloController { @RequestMapping("mo") //@ResponseBody public String mo(){ System.out.println("hello springboot"); return "success"; } } //当两个配置文件同时存在,则application.properties优先加载,不建议两种配置文件同时存在 //application.yml #自定义服务器启动的端口 server: port: 8989 //空格必须要有 servlet: context-path: /demo1 //空格必须要有 #springmvc的jsp解析器 spring: mvc: view: preifx: / suffix: .jsp datasource: type:com.alibaba.druid.pool.DruidDataSource driver-class-name:oracle.jdbc.OracleDriver url:jdbc:oracle:thin:@10.211.55.3:1521.xe username:hr password:hr mybatis: mapper-locations:classpath:com/mo/mapper/*Mapper.xml type-aliases-package:com.mo.entity
-
-
-
@SpringBootApplication注解
-
是由@SpringBootConfiguration、EnableAutoConfiguration、ComponentScan集成
- @SpringBootConfiguration:启动Springboot框架的配置功能,指定当前是个启动类
- @EnableAutoConfiguration:开启自动配置,将当前类声明为一个Spring的配置类
- @ComponentScan:自动到启动类的同级包结构下扫描相关的注解;扫描使用了Spring开发注解的包,扫描的范围是同级位置的包以及同级位置下的子包
-
Springboot底层实现方式之一,java bean配置形式
<bean id="u" class="com.mo.service.UserServiceImpl"></bean> //等价 @Configuration public class FactoryConfig{ @Bean //将当前方法的返回值对象纳入Spring工厂管理 public UserServiceImpl u(){ //此时通过工厂getBean获取对象时,id为方法名u return new UserServiceImpl(); } }
整合JSP
-
引入依赖
-
Springboot启动类默认启动的时候不会将jsp或html打包运行,需要手动配置启动的工作项目目录
-
Edit Configurations —> Enviroment —> Working directory
-
也可以插件的方式启动
<!--引入jsp运行插件--> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins>
-
还可以以jar包形式启动
-
-
项目的基本配置
-
App.java
/** * 用注解声明当前类是一个启动类 */ @SpringBootApplication //指定dao接口所在的包结构 @MapperScan("com.mo.dao") public class App { public static void main(String[] args) { //指定启动类,运行后会启动整个Web应用 SpringApplication.run(App.class,args); } }
-
Dao.java
@Repository public interface EmpDao { }
-
application.properties
#指定springboot内置tomcat启动的端口号 server.port=8989 #编写视图解析器 spring.mvc.view.prefix=/ spring.mvc.view.suffix=.jsp #整合mybatis相关的内容 spring.datasource.driver-class-name=oracle.jdbc.OracleDriver spring.datasource.url=jdbc:oracle:thin:@10.211.55.3:1521:xe spring.datasource.username=hr spring.datasource.password=hr #数据源 spring.datasource.type=org.apache.commons.dbcp.BasicDataSource #指定mapper文件路径 mybatis.mapper-loactions=classpath:com/mo/mapper/*Mapper.xml #指定实体类别名 mybatis.type-aliases-package=com.mo.entity
-
设置springboot日志级别
-
Springboot默认集成了logback日志工具,logback是log4j作者开发的一个产品,在效率上比log4j更高,升级版日志管理
-
关于日志常用的几种级别:
-
DEBUG --> INFO --> WARN --> ERROR,四种日志级别由低到高,级别越低输出信息越多,级别越高输出的信息越少
-
root(父日志):代表根目录,会全面监控项目中所有位置的日志处理输出
-
logger(子日志):用于监控指定位置下的日志的处理输出,主要区别为范围
#自定义日志输出级别 logging: level: root: info #springboot默认日志级别 root,整个项目范围内所有的日志级别 com.mo.dao: DEBUG #便于查看mybatis 针对某些特定的包设置日志级别 com.mo: DEBUG #此时包含子目录 #书写日志配置 logging.level.root=info logging.level.com.mo.controller=debug logging.level.com.mo.service=debug #指定日志输入文件名,默认会在当前项目的根目录下生成日志文件 logging.file=log.log #指定一个输出日志文件的目录,不需要指定文件名,默认日志文件名为spring.log #当指定了logging.file后logging.path的配置会失效 #logging.path=d://
-
程序中测试,在哪个阶段查看
@Controller @ReqeustMapping("emp") @Slf4j //测试日志 public String findAll(Model model){ //private Logger log = LoggerFactory.getLogger(EmpController.class);有@Slf4j注解时不需要写 @Autowired private EmpService empService; List<Emp> emps = empService.findAll(); model.addAttribute("emps",emps); //System.out.println()做测试时,因为调用的是IO,效率低,不采用 //使用日志调试项目 //log.debug("{}",emps) 设置了debug级别,比debug低的都不会输出 log.info("{}",emps); return "list"; }
-
测试
@RunWith(SpringRunner.class) //相当于SpringJuntiClassRunner的功能 @SpringBootTest(classes = {SpringbootDemo2App.class}) //指定启动类 public class TestEmpService{ @Autowired private EmpService empService; @Test public void test0(){ List<Emp> all = empService.findAll(); System.out.println(all); } }
-
-
自定义日志监控模版
logback.xml <?xml version="1.0" encoding="UTF-8" ?> <configuration> <!-- appender代表配置的一个日志输出方式(日志在控制台输出还是输出到一个文件)和输出格式的模版 ConsoleAppender:用于将日志输出到控制台--> <appender name="sout" class="ch.qos.logback.core.ConsoleAppender"> <!-- 指定输出日志格式处理的类 --> <layout class="ch.qos.logback.classic.PattrenLayout"> <!-- 具体指定日志输出的格式模版--> <pattern>%d{yyyy-MM-dd HH:mm:ss} %p %r [%t] %m %n</pattern> </layout> </appender> <!-- root根日志处理,通常只有一个 logback只会处理包含当前日志输出级别以及比他高的级别的日志输出 --> <root level="info"> <!-- 引用日志的输出处理模版--> <appender-ref ref="sout"></appender-ref> </root> <!-- logger子日志处理,子日志监控可以有多组配置 --> <logger name="com.mo.dao"></logger> </configuration>
配置文件按照不同环境的选择
-
application.yml:项目的发布可以灵活切换
-
application-dev.yml:开发环境
-
application-prod.yml:线上环境
spring: profiles: active: dev //此时使用dev spring: profiles: active: prod //此时使用prod 或 spring.profiles.active=dev
-
热部署
-
引入热部署依赖:有可能遇到问题,涉及到虚拟机
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
-
idea设置:Build,Execution,Deployment --> Compile --> 钩上Build project automatically
Springboot三种启动方式
-
启动类方式启动:要求启动类上面使用@SpringBootApplication
-
使用插件方式启动
-
打成war包部署到外部tomcat:需要手动排除Springboot内置的tomcat,然后打包
-
排除内部tomcat
<!--引入springboot的web支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--排除内部的tomcat--> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency>
-
给App换一个启动方式:继承SpringBootServletInitializer,覆盖configure方法,使用SpringApplicationBuilder启动
@SpringBootApplication public class App extends SpringBootServletInitializer { //使用builder方式启动应用 @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder){ return builder.source(App.class); } }
-
-
以jar包的形式启动
- 手动将pom中的packaging改成jar,代表以jar包的方式打包项目
- 执行mvn package进行打包,然后可以将打好的jar包直接放到一个具备java环境的服务器上运行
- 执行jar包启动java -jar 指定springboot项目的jar包运行
- jar包方式部署一般只给前端提供数据,主要用于前后端分离开发的项目,不做视图(JSP、HTML资源的部署),适合微服务和集群部署
-
docker技术做微服务,需要jar包方式
-
编码格式的处理
-
POST请求中文乱码处理
#开启http请求编码的处理,默认为true spring.http.encoding.enabled=true #application.properties #POST请求中文编码 spring.http.encoding.charset=UTF-8
-
GET请求中文乱码
#application.properties #修改springboot项目内置tomcat对get请求中文乱码的处理 server.tomcat.uri-encoding=UTF-8
-
插件乱码问题
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <!--避免乱码,给插件指定编码格式 --> <configuration> <!--强制使用这些参数--> <fork>true</fork> <jvmArguments>-Dfile.encoding=utf-8</jvmArguments> <!--指定启动类--> <mainClass>com.mo.App</mainClass> </configuration> </plugin>
-
-
自定义JSON中日期转换格式
public class User implements Serializable { private String username; private String password; //自定义JSON转换中日期类型的格式 @JsonFormat(pattern = "yyyy-MM-dd") private Date date; } @RequestMapping("test0") //@ResponseBody public String test0(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date){ System.out.println("test0:"+date); return "index"; }
-
接收日期格式也可以在配置文件中设置
#application.properties spring.mvc.data-format=yyyy-MM-dd
AOP开发
-
前置通知
-
编写切面类
//把这个类装入spring工厂 @Component // 将当前类定义为切面类 @Aspect public class BeforeAdvice { // 前置通知,里面写切入点函数 @Before("execution(* com.mo.service..*.*(..))") public void beforeAdvice(JoinPoint joinPoint){ //书写额外功能 System.out.println("额外功能的实现"); // 原始方法参数 Object[] args = joinPoint.getArgs(); // 原始方法签名 Signature signature = joinPoint.getSignature(); // 原始类的对象 Object target = joinPoint.getTarget(); System.out.println("args原始方法参数:"+args[0]); System.out.println("signature原始方法签名:"+signature.getName()); System.out.println("target原始类的对象:"+target.getClass()); } }
-
-
后置通知
@Component @Aspect public class MyAfterAdvice { //会把返回值注入 @AfterReturning(pointcut = "execution(* com.mo.service..*.*(..))",returning = "result") public Object afterAdvice(JoinPoint joinPoint,Object result){ System.out.println("额外功能后置通知"); return result; } }
-
环绕通知
@Component @Aspect @Slf4j public class AroundAdvice { @Around("execution(* com.mo.service..*.*(..))") public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { //原始方法前额外功能 System.out.println("环绕功能的前额外功能"); log.info("原始方法调用日志记录"); //手动调用原始方法 //proceedingJoinPoint与前置通知使用一致 Object o = proceedingJoinPoint.proceed(); // 原始方法后额外功能 System.out.println("环绕功能的后额外功能"); return null; } }
文件上传
-
springboot自动导入依赖
-
application.properties
#定义上传文件大小限制 #上传单个文件大小限制,默认1M,单位为字节 spring.servlet.multipart.max-file-size=20971520 #一次请求总的上传文件大小限制,默认10M,单位为字节 spring.servlet.multipart.max-request-size=20971520
-
jsp
<form action="${pageContext.request.contextPath }/file/upload" method="post" enctype="multipart/form-data"> <input type="file" name="upload"> <input type="submit" value="上传"> </form>
-
controller
@Controller @RequestMapping("file") public class FileController { @RequestMapping("upload") public String upload(MultipartFile upload, HttpSession session) throws IOException { //获取保存文件的位置,真是路径 String realPath = session.getServletContext().getRealPath("/upload"); String filename = upload.getOriginalFilename(); // 保存文件 upload.transferTo(new File(realPath+"/"+filename)); return "index"; } }
文件下载
-
controller
@RequestMapping("download") public void download(HttpServletResponse response,HttpSession session) throws IOException { //读取待下载文件 String realPath = session.getServletContext().getRealPath("/upload"); FileInputStream in = new FileInputStream(realPath + "/5.jpg"); //设置两个请求头:指定下载文件的类型,下载文件的保存 / 打开方式 response.setHeader("content-type", "image-jpeg"); response.setHeader("content-disposition","arrachment;filename=a.jpg"); IOUtils.copy(in,response.getOutputStream()); }
拦截器
-
编写拦截器
public class MyInterceptor1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("pre handler"); //true执行 return true; } }
-
注册拦截器,javabean形式
//作为一个配置类加入到Spring中 @Component public class RegistInterceptor implements WebMvcConfigurer { /** * 注册拦截器 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { InterceptorRegistration interceptor = registry.addInterceptor(new MyInterceptor1()); //配置拦截的范围 interceptor.addPathPatterns("/**"); //拦截所有 //路径不能带项目名 interceptor.excludePathPatterns("/target/test0"); //排除不拦截的,基于上面的范围排除 } }
全局异常处理
-
使用注解定义全局异常处理器
//声明为一个异常处理类,当程序运行过程中出现指定的异常类型,会自动进入全局的异常处理器,执行对应的异常处理方法 @ControllerAdvice public class ExceptionHandlerController { //参数是异常类型的类对象数组 @ExceptionHandler(NullPointerException.class) public String handleNullPointerException(Exception e){ //输出此时的异常,便于调错 e.printStackTrace(); System.out.println("异常处理器 1"); return "redirect:/error.jsp"; } //匹配优先级是先精确匹配,然后在匹配大范围 @ExceptionHandler(Exception.class) public String handleException(Exception e){ //输出此时的异常,便于调错 e.printStackTrace(); System.out.println("异常处理器 2"); return "redirect:/error.jsp"; } }
跨域问题
- 发生在js代码中向不是同一个应用(域名或IP或端口有一个不一致就属于不同的应用)的资源发起请求,获取数据的情况;跨域问题是浏览器提供的一种安全策略,不允许随便都能获取网站的数据