Springboot


SpringBoot

概述

  1. 起步依赖:告诉springboot需要什么功能,它就能引入需要的库,起步依赖其实就是利用maven传递依赖解析,把常用的库聚合在一起,组成了几个为特定功能而定制的依赖
  2. 自动配置:针对很多spring应用程序常见的功能,spring提供了自动依赖扫描,并进行自动配置

创建项目

  1. Spring Initializr(springboot初始化器)

  2. 选择需要的功能

    • Spring Web
    • mybatis
    • mysql驱动
    • lombok
    • devtools(开发工具)
  3. 修改了 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
    
  4. 添加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文件的问题:

  5. 添加mapper扫描注解

    @SpringBootApplication
    @MapperScan(basePackages = "com.neu.mapper")
    public class SpringbootDemo1Application {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootDemo1Application.class, args);
        }
    
    }
    

Mapper文件相关配置

  1. 把mapper.xml放到 resources目录下,与mapper接口对应的文件夹下,如

  2. 修改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分页插件

  1. 添加依赖

    <!--分页插件 pagehelper -->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.4.1</version>
    </dependency>
    
  2. 测试

    @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]}
    
  3. 设置(可选)

    #分页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

  1. 导入jar包

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
  2. 编写切面类

    @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()));
        }
    }
    

热部署

  1. 引入配置
<!-- SpringBoot 热部署组件 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>
  1. 配置静态自动编译
  1. 如何触发热部署

    1. 虽然idea会自动保存,但是触发时间不确定,可以手动触发保存 Ctrl + S

    2. 点击idea上面的 小锤子图标,build project也会触发热部署

文件上传

  1. 编写上传网页

    <form 
            action="${ pageContext.request.contextPath }/emp/upload" 
            method="post"
            enctype="multipart/form-data"
        >
            文件名:<input type="file" name="file">
            <input type="submit" value="提交">
        </form>
    
  2. 服务器端

    @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("文件上传成功!");
        }
    
  3. 多文件上传

    <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("文件上传成功!");
        }
    
  4. 设置上传尺寸大小

    #每个文件最大尺寸
    spring.servlet.multipart.max-file-size=5MB
    #设置请求最大尺寸
    spring.servlet.multipart.max-request-size=10MB
    

全局异常处理

  1. 意义:更友好和更安全

  2. 代码:

    @ControllerAdvice
    public class GlobalExceptionHandle {
    
        @ExceptionHandler(Exception.class)
        @ResponseBody
        public String exceptionHandler(Exception ex) {
            if(ex instanceof MaxUploadSizeExceededException) {
                return "文件超过规定大小";
            }
            
            return "服务器错误,请联系管理员!";
        }
    }
    

输出日志

  1. 导入依赖

            <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>
    
  2. 在resources目录下,添加配置文件:log4j2.xml

拦截器

  1. 拦截器类似于Servlet中的过滤器,用于对处理器进行预处理和后处理

  2. 创建一个拦截器

    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;
        }
    }
    
  3. 注册拦截器

    @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

  1. 定义:Rest是一种规范,一种编程风格,简单的说,就是利用http协议通过Get、Post、Put、Patch、Delete来操作具有URI标识的服务器资源,返回统一格式的资源信息,包括:JSON、xml等

  2. JSON:JavaScript对象表示法

    • {“name”:”tom”,”age”:20}
    • [10,true,”tom”,{“name”:”tom”,”age”:20}]
  3. 返回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;
          }
      }
      
    1. Http method方法:

      • get(select):从服务器取出资源(一项或多项)
      • post(insert):在服务器新建一个资源
      • put(update):更新服务器资源(完整更新)
      • patch(update):更新服务器资源(有选择更新)
      • delete(delete):删除服务器资源
    2. 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();
          }
      }
      
    3. post请求

      @PostMapping
      public int insert(@RequestBody Dept dept) {
          return deptService.insert(dept);
      }
      
    4. put请求

      @PutMapping
      public int update(@RequestBody Dept dept) {
          return deptService.update(dept);
      }
      

打包

  1. 打 jar 包

  2. 打 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

    • 测试:http://localhost:9000/war包名/资源url

    • 停止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页面目录加入

二、包含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文件里指将jsp页面目录加入到

3)指定 spring-boot-maven-plugin 版本为 1.4.2.RELEASE,其它版本的都不可以,具体原因不详,据说是个bug。

设置 targetPath 只能是 META-INF/resources。然后用这个版本最好指定一下启动类main函数,否则当你项目里面存在多个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

文章作者: FFFfrance
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 FFFfrance !