SpringBoot
概述
- 起步依赖:告诉springboot需要什么功能,它就能引入需要的库,起步依赖其实就是利用maven传递依赖解析,把常用的库聚合在一起,组成了几个为特定功能而定制的依赖
- 自动配置:针对很多spring应用程序常见的功能,spring提供了自动依赖扫描,并进行自动配置
创建项目
Spring Initializr(springboot初始化器)
选择需要的功能
- Spring Web
- mybatis
- mysql驱动
- lombok
- devtools(开发工具)
修改了 application.properties
#配置web服务器的端口号 server.port=8089 #配置数据源参数 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/neusoft?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root #配置视图解析器 spring.mvc.view.prefix=/WEB-INF/jsp/ spring.mvc.view.suffix=.jsp
添加jsp支持
<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <scope>provided</scope> </dependency>
idea中解决不能添加jsp文件的问题:
添加mapper扫描注解
@SpringBootApplication @MapperScan(basePackages = "com.neu.mapper") public class SpringbootDemo1Application { public static void main(String[] args) { SpringApplication.run(SpringbootDemo1Application.class, args); } }
Mapper文件相关配置
把mapper.xml放到 resources目录下,与mapper接口对应的文件夹下,如
修改pom.xml,并在maven窗口中执行刷新
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </build>
mybatis执行时显示sql
在application.properties或application.yml文件中配置对应mapper所在包的日志级别即可。
示列:com.neu.springbootdemodd.mapper 指向mapper 接口包路径地址
# 日志记录输出配置
logging.level.com.neu.springbootdemodd.mapper=debug
mybatis分页插件
添加依赖
<!--分页插件 pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.1</version> </dependency>
测试
@Test void testGetPaged(){ PageHelper.startPage(2,3); List<Dept> list = deptMapper.getAll(); PageInfo<Dept> pageInfo = new PageInfo<>(list); System.out.println(pageInfo); } 输出: PageInfo{pageNum=2, pageSize=3, size=3, startRow=4, endRow=6, total=11, pages=4, list=Page{count=true, pageNum=2, pageSize=3, startRow=3, endRow=6, total=11, pages=4, reasonable=false, pageSizeZero=false}[Dept(deptno=30, dname=SALES, loc=沈阳), Dept(deptno=33, dname=hr5, loc=南京), Dept(deptno=37, dname=hr, loc=sy)], prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, navigatePages=8, navigateFirstPage=1, navigateLastPage=4, navigatepageNums=[1, 2, 3, 4]}
设置(可选)
#分页pageHelper pagehelper: helperDialect: mysql reasonable: true #为了使用输入页数为负或者超出最大页时候使页数为最小或最大值 supportMethodsArguments: true params: count=countSql pageSizeZero: true ·helper-dialect: 配置使用哪种数据库语言,不配置的话pageHelper也会自动检测 ·reasonable: 配置分页参数合理化功能,默认是false。 #启用合理化时,如果pageNum<1会查询第一页,如果pageNum>总页数会查询最后一页; #禁用合理化时,如果pageNum<1或pageNum>总页数会返回空数据。 ·params: 为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值; 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。 ·support-methods-arguments: 支持通过Mapper接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 pageSizeZero pageSize=0 or RowBounds.Limit = 0的时候就不适用分页,但是返回对象还是PageInfo
Spring对mybatis事务的支持
注意:mysql只有InnoDB引擎支持事务
@Transactional
public int insert(Dept dept) {
int n = deptMapper.insert(dept);
deptMapper.insert(dept);
return n;
}
AOP
导入jar包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
编写切面类
@Configuration @EnableAspectJAutoProxy//开启切面自动代理 @Component @Aspect//切面 public class AOPUtil { //定义切入点 @Pointcut("execution (* com.neu.controller.*.*(..))") public void pointcut() { } @Before("pointcut()") public void before() { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(f.format(new Date())); } }
热部署
- 引入配置
<!-- SpringBoot 热部署组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
- 配置静态自动编译
如何触发热部署
虽然idea会自动保存,但是触发时间不确定,可以手动触发保存 Ctrl + S
点击idea上面的 小锤子图标,build project也会触发热部署
文件上传
编写上传网页
<form action="${ pageContext.request.contextPath }/emp/upload" method="post" enctype="multipart/form-data" > 文件名:<input type="file" name="file"> <input type="submit" value="提交"> </form>
服务器端
@RequestMapping("upload") public void upload(MultipartFile file,HttpServletRequest request, HttpServletResponse response) throws IllegalStateException, IOException { String path = request.getServletContext().getRealPath("/WEB-INF/upload"); if(file != null && !file.isEmpty()) { String filename = file.getOriginalFilename(); File f = new File(path, filename); //保存 file.transferTo(f); } response.setContentType("text/html;charset=utf-8"); response.getWriter().append("文件上传成功!"); }
多文件上传
<form action="${ pageContext.request.contextPath }/emp/upload" method="post" enctype="multipart/form-data" > 文件名:<input type="file" name="files"><br> 文件名:<input type="file" name="files"><br> 文件名:<input type="file" name="files"><br> <input type="submit" value="提交"> </form>
@RequestMapping("upload") public void upload(@RequestParam("files") MultipartFile[] files,HttpServletRequest request, HttpServletResponse response) throws IllegalStateException, IOException { String path = request.getServletContext().getRealPath("/WEB-INF/upload"); for(MultipartFile file : files) { if(file != null && !file.isEmpty()) { String filename = file.getOriginalFilename(); File f = new File(path, filename); //保存 file.transferTo(f); } } response.setContentType("text/html;charset=utf-8"); response.getWriter().append("文件上传成功!"); }
设置上传尺寸大小
#每个文件最大尺寸 spring.servlet.multipart.max-file-size=5MB #设置请求最大尺寸 spring.servlet.multipart.max-request-size=10MB
全局异常处理
意义:更友好和更安全
代码:
@ControllerAdvice public class GlobalExceptionHandle { @ExceptionHandler(Exception.class) @ResponseBody public String exceptionHandler(Exception ex) { if(ex instanceof MaxUploadSizeExceededException) { return "文件超过规定大小"; } return "服务器错误,请联系管理员!"; } }
输出日志
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> <!-- <version>2.4.6</version> --> </dependency>
在resources目录下,添加配置文件:log4j2.xml
拦截器
拦截器类似于Servlet中的过滤器,用于对处理器进行预处理和后处理
创建一个拦截器
public class LoginCheckInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Object username = session.getAttribute("username"); if(username != null) { //表示放行,不拦截 return true; } response.setContentType("text/html;charset=utf-8"); response.getWriter().print("没有权限,不能访问!!!"); return false; } }
注册拦截器
@Configuration public class SpringMVCConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginCheckInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/","/user/login"); } }
注册视图控制器
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("user/login");
registry.addViewController("/emp/getUpload").setViewName("emp/upload");
}
}
RESTFul
定义:Rest是一种规范,一种编程风格,简单的说,就是利用http协议通过Get、Post、Put、Patch、Delete来操作具有URI标识的服务器资源,返回统一格式的资源信息,包括:JSON、xml等
JSON:JavaScript对象表示法
- {“name”:”tom”,”age”:20}
- [10,true,”tom”,{“name”:”tom”,”age”:20}]
返回JSON数据
@Controller @RequestMapping("emp") public class EmpController { @RequestMapping("getAll2") @ResponseBody public List<Emp> getAll2() { List<Emp> list = empService.getAll(); return list; } }
@RestController @RequestMapping("emp") public class EmpController { @RequestMapping("getAll2") public List<Emp> getAll2() { List<Emp> list = empService.getAll(); return list; } }
Http method方法:
- get(select):从服务器取出资源(一项或多项)
- post(insert):在服务器新建一个资源
- put(update):更新服务器资源(完整更新)
- patch(update):更新服务器资源(有选择更新)
- delete(delete):删除服务器资源
get请求
@RestController @RequestMapping("dept2") public class RestDeptController { @Autowired private DeptService deptService; //dept2/10 @GetMapping("{deptno}") public Dept getById(@PathVariable("deptno")int deptno) { return deptService.getById(deptno); } @GetMapping public List<Dept> getAll() { return deptService.getAll(); } @GetMapping("{dname}/{loc}") public List<Dept> getById(@PathVariable("dname") String dname,@PathVariable("loc") String loc) { System.out.println(dname); System.out.println(loc); return deptService.getAll(); } }
post请求
@PostMapping public int insert(@RequestBody Dept dept) { return deptService.insert(dept); }
put请求
@PutMapping public int update(@RequestBody Dept dept) { return deptService.update(dept); }
打包
打 jar 包
- 关闭原来的项目
- run as=》maven build =》 clean package
- 运行:java -jar jar包路径
- 测试:http://localhost:8089/dept/hr/sy
打 war 包
修改打包方式:war
添加启动配置类
public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Springbootdemo2Application.class); } }
run as=》maven build =》clean package
把生成的war包拷贝到 tomcat安装目录 /webapps 文件夹下
启动 tomcat服务器 : bin/startup.bat
停止tomcat服务
删除 war 包
可以把war包解压的所有内容剪切到 ROOT 文件夹下,把这个应用作为 根应用
打包问题:
Invalid bound statement (not found): com.neu.mapper.DeptMapper.getById
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>${project.basedir}/src/main/resources</directory> </resource> </resources> </build>
springboot打成jar包无法访问jsp
背景
以前老项目迁成springboot项目,里面有jsp页面,但是在打成jar包后,使用java -jar xxx.jar 发现并不能访问jsp页面,但其他接口能正常使用。ps:项目如果是直接从启动类main方法启动是可以访问。
存在问题
一、jar包未含jsp文件
旧spring mvc项目 jsp 放在webapp目录下,spring-boot-maven-plugin 打包默认是不含该目录的,应在pon文件
二、包含jsp文件仍访问不了
需要把spring-boot-maven-plugin 版本改为 1.4.2.RELEASE,其它版本的都不可以。
详细方案
1)检查 pom 文件是否添加已对 jsp 页面的依赖:
<!-- tomcat JSP 的支持.-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>compile</scope>
</dependency>
2)对jar包进行解压,进入解压目录查看是否有jsp页面,命令如下:
unzip xxx.jar
如果发现目录下没有jsp页面,则需要在pon文件
3)指定 spring-boot-maven-plugin 版本为 1.4.2.RELEASE,其它版本的都不可以,具体原因不详,据说是个bug。
设置 targetPath 只能是 META-INF/resources。然后用这个版本最好指定一下启动类main函数
<!-- jsp加入resources,指定插件版本-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.4.2.RELEASE</version>
<configuration>
<mainClass>com.xxx.xxx.SpringbootApplication</mainClass>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>**/**</include>
</includes>
</resource>
</resources>
</build>
4)在配置文件中加入前缀、后缀,这样项目启动就能正常访问到 jsp 页面了,此处项目目录为:
spring:
mvc:
servlet:
load-on-startup: 1
view:
suffix: .jsp
prefix: /WEB-INF/views/
ps:本地开发修改页面实时生效的配置:
server:
port: 8181
servlet:
jsp:
init-parameters:
development: true