Java经典框架之SpringBoot

SpringBoot

Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。
  

课程内容的介绍

1. SpringBoot基础
2. SpringBoot高级 
  

一、SpringBoot基础

1. SpringBoot概念
官网:https://spring.io/
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
SpringBoot是由Pivotal团队在2013年开始研发、2014年4月发布第一个版本的全新开源的轻量级框架。它基于Spring4.0设计,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决。
  
SpringBoot所具备的特征有:
(1)可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
(2)内嵌Tomcat或Jetty等Servlet容器;
(3)提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;
(4)尽可能自动配置Spring容器;
(5)提供准备好的特性,如指标、健康检查和外部化配置;
(6)绝对没有代码生成,不需要XML配置。
  
SpringBoot框架中还有两个非常重要的策略:开箱即用和约定优于配置。开箱即用,Outofbox,是指在开发过程中,通过在MAVEN项目的pom文件中添加相关依赖包,然后使用对应注解来代替繁琐的XML配置文件以管理对象的生命周期。这个特点使得开发人员摆脱了复杂的配置工作以及依赖的管理工作,更加专注于业务逻辑。约定优于配置,Convention over configuration,是一种由SpringBoot本身来配置目标结构,由开发者在结构中添加信息的软件设计范式。这一特点虽降低了部分灵活性,增加了BUG定位的复杂性,但减少了开发人员需要做出决定的数量,同时减少了大量的XML配置,并且可以将代码编译、测试和打包等工作自动化。
SpringBoot应用系统开发模板的基本架构设计从前端到后台进行说明:前端常使用模板引擎,主要有FreeMarker和Thymeleaf,它们都是用Java语言编写的,渲染模板并输出相应文本,使得界面的设计与应用的逻辑分离,同时前端开发还会使用到Bootstrap、AngularJS、JQuery等;在浏览器的数据传输格式上采用Json,非xml,同时提供RESTfulAPI;SpringMVC框架用于数据到达服务器后处理请求;到数据访问层主要有Hibernate、MyBatis、JPA等持久层框架;数据库常用MySQL;开发工具推荐IntelliJIDEA。
  
2. SpringBoot项目构建
SpringBoot项目的构建方式本身是非常简单的,实现的方式也有多种。
  
2.1 手动创建
我们通过基本的Maven项目来手动配置一个SpringBoot。
    
2.1.1 创建MAVEN项目
创建一个普通的Maven项目即可。

Java经典框架之SpringBoot_第1张图片

    
2.1.2 添加依赖
创建一个SpringBoot的Web项目,我们需要添加对应的依赖。


    4.0.0

    com.bobo
    SpringBootDemo01
    1.0-SNAPSHOT

    
    
        spring-boot-starter-parent
        org.springframework.boot
        2.3.8.RELEASE
    

    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
    


    
2.1.3 创建启动类
我们要启动当前项目需要创建一个Java启动类。
package com.bobo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * SpringBoot项目的启动类
 */
@SpringBootApplication
public class AppStart {

    /**
     * 程序启动的入口
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(AppStart.class,args);
    }
}
  
2.1.4 启动程序
执行我们的主方法即可。

Java经典框架之SpringBoot_第2张图片

访问出现404,说明服务启动成功,只是请求访问的资源不存在。

Java经典框架之SpringBoot_第3张图片

   
2.2 在线构建
我们也可以通过SpringBoot提供的在线地址创建我们的SpringBoot项:https://start.spring.io/

Java经典框架之SpringBoot_第4张图片

  
在线生成我们的SpringBoot项目,解压后可以直接导入。
 
2.3 IDEA直接创建
IDEA工具可以直接通过在线创建的工具来直接生成,帮助我们简化了下载解压缩的步骤。

Java经典框架之SpringBoot_第5张图片

Java经典框架之SpringBoot_第6张图片

Java经典框架之SpringBoot_第7张图片

Java经典框架之SpringBoot_第8张图片

到此创建完成。
  
3. SpringBoot基本使用
3.1 自定义控制器
我们创建的是一个基于SpringBoot的WEB项目,那么怎么处理客户端提交的请求呢?这时我们可以直接在启动器所在的子目录下创建对应的Controller即可。
package com.bobo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/*@Controller
@ResponseBody*/
@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        System.out.println("hello ...);
        return "Hello ...";
    }
}
    
访问即可

Java经典框架之SpringBoot_第9张图片

       
为什么能够扫描到这个@Controller注解,根本原因是在我们的启动器中的那个@SpringBootApplication注解,这个注解本身是一个组合注解。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 以上四个是JAVA中提供的元注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
  

Java经典框架之SpringBoot_第10张图片

   
3.2 静态资源
在SpringBoot项目中默认的静态资源【html,css,js,图片....】是放置在resource/static目录中。

Java经典框架之SpringBoot_第11张图片

    
效果

Java经典框架之SpringBoot_第12张图片

  
3.3 定制Banner
如果我们想要修改服务启动时的那个banner图标,我们只需要在resource目录下创建一个banner.txt文件,然后将我们要显示的信息写入即可http://patorjk.com/software/taag/#p=display&f=Graffiti&t=HELLO
  

Java经典框架之SpringBoot_第13张图片

  

Java经典框架之SpringBoot_第14张图片

    
当然我们也可以不显示Banner信息。
package com.bobo;

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * @SpringBootApplication 组合注解
 * @ComponentScan 可以直接扫描路径
 *                如果没有指定要扫描的特定的路径,
 *                那么默认的是会把当前注解所在的类的包及其子包作为扫描路径
 */
@SpringBootApplication
public class SpringBootDemo03Application {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(SpringBootDemo03Application.class);
        app.setBannerMode(Banner.Mode.OFF); // 关闭掉Banner
        app.run(args);
    }

}
  
3.4 属性文件
在resource目录下的application.properties文件。
   
3.4.1 默认设置
我们可以通过application.properties文件来修改系统默认的属性,比如修改Tomcat相关配置信息。
server.port=8082
server.servlet.context-path=/springboot
   
3.4.2 自定义属性
我们可以在application.properties文件中自定义属性,供我们在代码中使用。
   
自定义属性
# 默认属性修改
server.port=8082
server.servlet.context-path=/springboot
# 自定义属性
user.userName=admin
user.realName=波波
user.address=湖南长沙
  
获取自定义属性
package com.bobo.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/*@Controller
@ResponseBody*/
@RestController
public class HelloController {

    @Value(value = "${user.userName}")
    private String userName;
    @Value(value = "${user.realName}")
    private String realName;
    @Value(value = "${user.address}")
    private String address;

    @RequestMapping("/hello")
    public String hello(){
        System.out.println("hello ..."+ userName + "  " + realName + " " + address);
        return "Hello ...";
    }
}
     
出现乱码的情况

Java经典框架之SpringBoot_第15张图片

  
解决方法

Java经典框架之SpringBoot_第16张图片

    
修改了乱码后的效果

Java经典框架之SpringBoot_第17张图片

    
3.4.3 yml文件
yml是我们在配置系统属性或者自定义属性的另外一种方式。
user.hello.username=a
user.hello.password=123
user.hello.address=cs
user.hello.age=1
  
改成yml
user:
    hello:
        username:a
        password:123
        address:cs
        age:1
  
3.5 日志
SpringBoot中支持 JavaUtil Logging, Log4J, Log4J2和Logback作为日志框架,而在SpringBoot中默认支持的是Logback作为日志框架。
    
简单配置
# 日志配置
#logging.file.path=d:/tools/log
logging.file.name=d:/tools/log/log.log
logging.level.org.springframework.web=DEBUG
  

Java经典框架之SpringBoot_第18张图片

     
引入日志文件的扩展配置文件


    
    
    
    

    
    
    
    

    
    
        
        
            
            ${LOG_HOME}/%d{yyyyMMdd}/${APP_NAME}.log
            
            15
        
        
        
            
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
            
            
            utf8
        
        
        
            100MB
        
    

    
    
        
        
            
            
        

        
        
        
        
    
    
        
        
            
            
        
    
    
引入

Java经典框架之SpringBoot_第19张图片

   
3.6 Profile
项目开发中会出现开发环境的切换,为了更好的处理我们可以通过Profile来实现,之前在Spring的阶段就已经给大家介绍过了Profile,但是实现相对复杂了点,在SpringBoot中也提供了对Profile的支持,而且更加简化,创建对应的属性文件。
  
开发环境
user.host=192.168.100.120
   
生产环境
user.host=192.168.111.123
  
文件名称的命名规则是 application-环境.properties
  

Java经典框架之SpringBoot_第20张图片

  
要让哪个文件生效,我们只需要在application.properties文件中指定即可。
  

Java经典框架之SpringBoot_第21张图片

  
测试效果
  

Java经典框架之SpringBoot_第22张图片

  
3.7 静态资源文件
在SpringBoot项目中默认的存放路径是在static目录下,但是实际开发的时候有可能我们需要调整资源的目录。
   
在main目录下创建一个webapp目录 设置类型为 ResourceRoot。

Java经典框架之SpringBoot_第23张图片

   
可以直接访问
  

Java经典框架之SpringBoot_第24张图片

  
自定义目录
有些情况下我们需要将特定的目录作为我们存放静态资源文件的目录。
## 设置自定义的路径
spring.mvc.static-path-pattern=/**
## 覆盖掉默认的配置录
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,class path:/sfile/
   

Java经典框架之SpringBoot_第25张图片

  

Java经典框架之SpringBoot_第26张图片

   
3.8 Servlet操作
我们在项目开发过程中可以要碰到直接操作Servlet的情况,这时我们应该怎么去实现。
  
3.8.1 Servlet
第一种方式
定义Servlet
package com.bobo.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name="firstServlet",urlPatterns = "/first")
public class FirstServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("--firstServlet -- doGet 方法");
        PrintWriter writer = resp.getWriter();
        writer.write("success");
        writer.flush();
        writer.close();
    }
}
     
在启动类中添加扫描的注解。
@SpringBootApplication
// 在SpringBoot项目启动的时候会扫描 @WebServlet注解
@ServletComponentScan
public class SpringbootDemo06Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootDemo06Application.class, args);
    }
}
   
测试访问

      
第二种方式
创建Servlet,不用添加WebServlet注解。
package com.bobo.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


public class SecondServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("--secondServlet -- doGet 方法");
        PrintWriter writer = resp.getWriter();
        writer.write("success");
        writer.flush();
        writer.close();
    }
}
     
在启动类中注入ServletRegistrationBean对象。
@SpringBootApplication
// 在SpringBoot项目启动的时候会扫描 @WebServlet注解
@ServletComponentScan
public class SpringbootDemo06Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootDemo06Application.class, args);
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean(){
        ServletRegistrationBean bean = new ServletRegistrationBean(new SecondServlet());
        bean.addUrlMappings("/second");
        return bean;
    }
}
  
测试

Java经典框架之SpringBoot_第27张图片

    
3.8.2 Filter
第一种方式
创建过滤器
@WebFilter(urlPatterns = "/first")
public class FirstFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("FirstFilter before");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("FirstFilter end");
    }
}
   
在启动器中添加注解。

Java经典框架之SpringBoot_第28张图片

  
测试

Java经典框架之SpringBoot_第29张图片

  
第二种方式
在该过滤器中我们不用添加对应的注解。
package com.bobo.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;


public class SecondFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("SecondFilter before");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("SecondFilter end");
    }
}
   
启动器中注入 注册器。
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean bean = new FilterRegistrationBean(new SecondFilter());
        bean.addUrlPatterns("/second");
        return bean;
    }
  
测试

Java经典框架之SpringBoot_第30张图片

  
3.8.3 Listener
第一种方式
package com.bobo.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class FirstListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("FirstListener ... 初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("FirstListener ... 销毁");
    }
}
  
启动器中注解

Java经典框架之SpringBoot_第31张图片

  
测试效果

  
第二种方式
package com.bobo.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;


public class SecondListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("SecondListener ... 初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("SecondListener ... 销毁");
    }
}
    @Bean
    public ServletListenerRegistrationBean servletListenerRegistrationBean(){
        return new ServletListenerRegistrationBean(new SecondListener());
    }
  
测试

Java经典框架之SpringBoot_第32张图片

 
3.9 文件上传
3.9.1 表单页面



    
    用户管理



    

文件上传案例:



  
3.9.2 控制器
package com.bobo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

@RestController
@RequestMapping("/user")
public class UserContoller {

    @RequestMapping("/upload")
    public String fileUpload(String username, MultipartFile upload) throws IOException {
        System.out.println(username + " " + upload.getOriginalFilename());
        upload.transferTo(new File("d:/tools/",upload.getOriginalFilename()));
        return "success";
    }


}
  
3.9.3 属性文件设置
server.port=8082

spring.servlet.multipart.enabled=true
# 设置单个文件上传的大小
spring.servlet.multipart.max-file-size=20MB
# 设置一次请求上传文件的总的大小
spring.servlet.multipart.max-request-size=200MB
  
3.9.4 测试

Java经典框架之SpringBoot_第33张图片

  

Java经典框架之SpringBoot_第34张图片

 
上传成功的文件

Java经典框架之SpringBoot_第35张图片

       
4.SpringBoot基本应用
4.1 Freemaker
FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
   
http://freemarker.foofun.cn/
  
JavaEE中的两种开发方式
前后端不分离
        要求程序员要掌握js,为了简化页面开发,引入页面模板,页面模板整体上来说又可以分为两大类。
   
前端模板
前端模板就是后缀为html的模板,代表就是Thymeleaf,这种模板有一个好处就是不需要服务端解析就能直接在浏览器中打开。
   
后端模板
必须经过服务端解析才能被浏览器展示出来的模板。
        JSP
        Freemarker
        velocity
  

前后端分离
前后端分离的时候,后端纯粹只是接口,没有任何页面。所有的页面由前端完成,前端会使用相关的模板。
        Vue
        AngularJS
        React
  
4.2 整合Freemaker
4.2.1 添加依赖

    org.springframework.boot
    spring-boot-starter-freemarker
  
4.2.2 配置
我们在属性文件中设置视图解析器的前后缀。
spring.freemarker.suffix=.ftl
   
4.2.3 创建Freemaker文件
然后我们在系统的模板文件中创建Freemaker文件,注意该文件为一个后缀为 .ftl 的文件。

    
        Freemaker
        
    
    
        

Hello Freemark ...

  
4.2.4 控制器
因为在 template 目录下的文件是没法直接访问的,而且我们也需要先在服务端获取数据绑定数据后再在页面模板文件中呈现,所以请求先到控制器,然后通过模板引擎解析模板文件生成具体的HTML页面响应客户。
@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/query")
    public String query(){
        System.out.println("query ....");
        return "user";
    }
}
   
4.2.5 测试
直接启动服务,访问看效果。

Java经典框架之SpringBoot_第36张图片

  

Java经典框架之SpringBoot_第37张图片

  
这就表示整合成功了。
   

4.3 Freemaker的基本应用
接下来介绍下如果在Freemaker中绑定数据。
  
4.3.1 绑定单个数据
我们在Model中绑定的是单个数据,怎么在ftl文件中绑定呢?
    /**
     * 基本数据类型
     * 自定义数据类型
     * 数据容器
     * @param model
     * @return
     */
    @RequestMapping("/query")
    public String query(Model model){
        System.out.println("query ....");
        model.addAttribute("userName","波波老师");
        model.addAttribute("age",18);
        model.addAttribute("address","湖南长沙");
        model.addAttribute("flag",true);
        model.addAttribute("birth",new Date());
        return "user";
    }
     
字符和数字类型我们可以通过EL表达式直接取出来。

    
        Freemaker
        
    
    
        

Hello Freemark ...

${userName}
${age}
   
boolean不能直接转换为string类型。

Java经典框架之SpringBoot_第38张图片

  
这时我们要通过内部的转换函数来处理。

    
        Freemaker
        
    
    
        

Hello Freemark ...

${userName}
${age}
${address}
${flag?string("真","假")}
      

Java经典框架之SpringBoot_第39张图片

      

    
        Freemaker
        
    
    
        

Hello Freemark ...

${userName}
${age}
${address}
${flag?string("真","假")}
${birth}
      
时间类型也需要转换。

Java经典框架之SpringBoot_第40张图片

   

    
        Freemaker
        
    
    
        

Hello Freemark ...

${userName}
${age}
${address}
${flag?string("真","假")}
${birth?string("yyyy-MM-dd")}
     

Java经典框架之SpringBoot_第41张图片

     
4.3.2 单个数据处理
我们服务端绑定的单个数据,比如字符串或者数字,我们可能需要对这些数据做出调整,比如数字要四舍五入,字符串我们需要截取等操作。

    
        Freemaker
        
    
    
        

Hello Freemark ...

${userName}
${age}
${address}
${flag?string("真","假")}
${birth?string("yyyy-MM-dd")}

<#-- 注释符 --> <#assign x=3.1415> <#assign y=6> x=${x}
y=${y}
#{x;M2}
#{x;m2}
#{y;M2}
#{y;m2}
     

Java经典框架之SpringBoot_第42张图片

  
字符串拼接处理
<#assign hello="hello freemarker" >
<#-- 字符串拼接 -->
HELLO-${hello}
<#-- EL表达式中的常量表示 --> ${'HELLO|'+hello}
<#-- 常量中使用数据 --> ${'HELLO*${hello}'}
${userName}----${hello}
${userName+'-->' + hello}
   

Java经典框架之SpringBoot_第43张图片

  
字符串截取
${hello}
${hello[1]}
${hello[4]}
${hello[1..6]}
${hello[3..]}
  

Java经典框架之SpringBoot_第44张图片

     
4.3.3 自定义对象
@RequestMapping("/query1")
public String query1(Model model){
    User user = new User(666,"admin","123456");
    model.addAttribute("user",user);
    return "user1";
}

    
        Freemaker
        
    
    
        <#-- 自定义对象 -->
        ${user.id}
--> <#--${user[id]}
--> ${user.userName}
-->${user['userName']}
${user.password}
   

Java经典框架之SpringBoot_第45张图片

      
4.3.4 集合对象
    @RequestMapping("/query1")
    public String query1(Model model){
        User user = new User(666,"admin","123456");
        model.addAttribute("user",user);
        Map map = new HashMap<>();
        map.put("user",user);
        List list = Arrays.asList("张三","李四","王五");
        List list1 = Arrays.asList("1111","2222","3333");
        model.addAttribute("list",list);
        model.addAttribute("list1",list1);
        model.addAttribute("map",map);
        return "user1";
    }
   

Java经典框架之SpringBoot_第46张图片

    
4.3.5 算数运算
算数运算包含基本的四则运算和求模运算,运算符有:
加法: +
减法: -
乘法: *
除法: /
求模 (求余): %

    
        Freemaker
        
    
    
        

算术运算符:


${99+100*30}
${99/7}
${(99/7)?int}
${55%3}
  

Java经典框架之SpringBoot_第47张图片

     
4.3.6 比较运算符

Java经典框架之SpringBoot_第48张图片

  
4.3.7 逻辑操作
常用的逻辑操作符:
逻辑 或: ||
逻辑 与: &&
逻辑 非: !
    
逻辑操作符仅仅在布尔值之间有效,若用在其他类型将会产生错误导致模板执行中止。
  
4.3.8 内置函数
内建函数就像FreeMarker在对象中添加的方法一样。 要防止和实际方法和其它子变量的命名冲突,则不能使用点 (.),这里使用问号 (?)来和父对象分隔开。 比如,想要保证 path 有起始的 / ,那么可以这么来写: path?ensure_starts_with(’/’)。 path 后的Java对象(通常就是 String) 并没有这样的方法,这是FreeMarker添加的。为了简洁,如果方法没有参数, 那么就可以忽略 (),比如想要获取 path 的长度,就可以写作:path?length, 而不是 path?length()。

Java经典框架之SpringBoot_第49张图片

     
更多内置函数见此:http://freemarker.foofun.cn/ref_builtins.html
   

    
        Freemaker
        
    
    
    

算术运算符:


${99+100*30}
${99/7}
${(99/7)?int}
${55%3}

内建函数:

<#assign hello="Hello FreeMarker"> <#assign page="HELLO"> ${hello}
${page}
${page?html}
${hello?upper_case}
${hello?lower_case}
${now?date}
${now?datetime}
${now?time}
  

Java经典框架之SpringBoot_第50张图片

     
4.3.9 分支和循环
if语句,switch语句已经循环语句,基本的语法格式和我们在Java中使用的是一样的。我们只需要注意下在具体的使用格式上。

    
        Freemaker
        
    
    
    

算术运算符:


${99+100*30}
${99/7}
${(99/7)?int}
${55%3}

内建函数:

<#assign hello="Hello FreeMarker"> <#assign page="HELLO"> ${hello}
${page}
${page?html}
${hello?upper_case}
${hello?lower_case}
${now?date}
${now?datetime}
${now?time}

<#assign age = 18 > <#if age == 18> 等于18 <#elseif age gt 18 > 大于18 <#else > 小于18 null的判断:
<#assign mypage="a"> <#-- ?? 检测值是否存在 --> <#if mypage??> mypage存在 <#else > mypage不存在
<#assign i=3> <#switch i> <#case 1> ok <#break > <#case 2> ok2 <#break > <#case 3> ok3 <#break > <#default > ok4 <#list list as obj> <#if obj=='李四'> <#break > ${obj}
<#assign aaa=555> <#-- !的使用-->
${aaa!"666"}
   

Java经典框架之SpringBoot_第51张图片

   
5.综合案例
前面介绍了Freemaker,这节介绍SpringBoot整合MyBatis,同时结合Freemaker展现数据。
   
5.1 项目创建
添加相关的依赖


    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.9.RELEASE
         
    
    com.bobo
    springboot-demo09
    0.0.1-SNAPSHOT
    springboot-demo09
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-freemarker
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            1.3.2
        
        
            mysql
            mysql-connector-java
        
        
            com.alibaba
            druid
            1.0.14
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


     
添加相关的配置文件
server.port=8082

# 配置JDBC的相关信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/logistics?
characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

# 配置连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

# 配置MyBatis的package 设置别名
mybatis.type-aliases-package=com.bobo.pojo
     
创建实体对象
package com.bobo.pojo;

public class User {
    private String user_id    ;
    private String user_name  ;
    private String real_name  ;
    private String password   ;
    private String email      ;
    private String phone      ;
    private String u1         ;
    private String u2         ;

    public String getUser_id() {
        return user_id;
    }

    public void setUser_id(String user_id) {
        this.user_id = user_id;
    }

    public String getUser_name() {
        return user_name;
    }

    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }

    public String getReal_name() {
        return real_name;
    }

    public void setReal_name(String real_name) {
        this.real_name = real_name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getU1() {
        return u1;
    }

    public void setU1(String u1) {
        this.u1 = u1;
    }

    public String getU2() {
        return u2;
    }

    public void setU2(String u2) {
        this.u2 = u2;
    }
}
   
5.2 查询用户信息
创建接口。
package com.bobo.mapper;

import com.bobo.pojo.User;

import java.util.List;

public interface UserMapper {

    List query();

}
      
创建映射文件。



    
   
属性文件中添加Mapper映射文件的路径。

Java经典框架之SpringBoot_第52张图片

  
创建Service
package com.bobo.service;

import com.bobo.pojo.User;

import java.util.List;

public interface IUserService {

    List query();

}
package com.bobo.service.impl;

import com.bobo.mapper.UserMapper;
import com.bobo.pojo.User;
import com.bobo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper mapper;

    @Override
    public List query() {
        return mapper.query();
    }

}
   
创建控制器
package com.bobo.controller;

import com.bobo.pojo.User;
import com.bobo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserService service;

    @RequestMapping("/query")
    public String query(Model model){
        List list = service.query();
        model.addAttribute("list",list);
        return "/user";
    }

}
  
属性文件中配置Freemaker的后缀。

Java经典框架之SpringBoot_第53张图片

  
创建Freemaker模板文件,并且展示数据。

    
        用户管理
        
    
    
        

用户管理

<#list list as user>
编号 账号 姓名 邮箱 电话 操作
${user.user_id} ${user.user_name} ${user.real_name!""} ${user.email!""} ${user.phone!""} ...
   
启动操作之前我们需要添加 MyBatis接口的扫描路径。

Java经典框架之SpringBoot_第54张图片

  
访问测试

Java经典框架之SpringBoot_第55张图片

   
5.3 添加用户

    
        用户管理
        
    
    
        

用户管理





    
5.4 更新用户

    
        用户管理
        
    
    
        

用户管理





     
5.5 删除用户

    
        用户管理
        
    
    
        

用户管理

添加用户

<#list list as user>
编号 账号 姓名 邮箱 电话 操作
${user.user_id} ${user.user_name} ${user.real_name!""} ${user.email!""} ${user.phone!""} 更新 删除
   
6. Thymeleaf
Thymeleaf是SpringBoot中推荐使用的前端模板框架。所以比较重要。
  
6.1 SpringBoot整合
创建一个SpringBoot项目,然后添加对应的依赖。


    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.9.RELEASE
         
    
    com.bobo
    springboot-demo10
    0.0.1-SNAPSHOT
    springboot-demo10
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        

        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


     
创建Thymeleaf文件,Thymeleaf的后缀就是html,我在template目录下直接创建一个html页面即可,但是为了能够使用Thymeleaf中的标签提示,我们添加对应的xmlns即可。



    
    Thymeleaf介绍


    

Hello Thymeleaf

  
添加跳转的控制器。
@Controller
public class UserController {

    @RequestMapping("/hello")
    public String hello(){
        System.out.println("hello ....");
        return "/user";
    }
}
   
启动服务测试

Java经典框架之SpringBoot_第56张图片

  
访问成功,说明整合搞定。
  
6.2 Thymeleaf基本使用
Thymeleaf表达式只能放置在Thymeleaf的自定义属性中(html标签中)。
  
6.2.1 变量输出
控制器中绑定数据。
@RequestMapping("/hello")
public String hello(Model model){
    System.out.println("hello ....");
    model.addAttribute("hello","Hello Thymeleaf");
    model.addAttribute("msg","hahaha");
    model.addAttribute("now",new Date());
    model.addAttribute("flag",true);
    model.addAttribute("age",18);
    return "/user";
}
  
模板文件



    
    Thymeleaf介绍


    

Hello Thymeleaf






th:value的使用



   
显示效果

Java经典框架之SpringBoot_第57张图片

  
6.2.2 内置函数
我们通过上面的案例发现显示Model中的数据很方便,但是显示的数据的格式可能不满足我们的需求,这时我们需要调整就需要借助内置的函数来帮助我们实现,我们主要介绍字符串和时间相关的函数。
  
注意点
1. 调用内置函数对象一定要使用#
2. 大部分的内置函数都以 s 结尾, 比如 strings numbers dates
  
字符串的处理



    
    Thymeleaf介绍


    

string类型介绍

hello:
hello是否为空:
hello字符串是否包含"th":
hello字符串是否包含"Th":
hello以H开头:
hello以a开头:
hello以H结尾:
hello以a结尾:
hello的长度:
hello都大写:
hello都小写:
   

Java经典框架之SpringBoot_第58张图片

  
日期时间类型的处理

日期时间处理

时间:
时间:
时间:
时间:
时间:
年份:
月份:
日期:
本周的第几天:
小时:
  

Java经典框架之SpringBoot_第59张图片

  
6.2.3 条件判断



    
    Thymeleaf介绍



    

条件判断

if语句


or的使用11 or的使用12
and的使用21 and的使用22
not的使用11 not的使用22


17岁
18岁
19岁
其他...
    

Java经典框架之SpringBoot_第60张图片

  
6.2.4 循环语句



    
    Thymeleaf介绍



    

循环判断



     


           
   

Java经典框架之SpringBoot_第61张图片

  
6.2.5 域对象的操作
也就是我们怎么在Thymeleaf中获取三大作用域中绑定的数据。
@RequestMapping("/hello4")
public String hello4(HttpServletRequest request){
    request.setAttribute("req","request msg ...");
    request.getSession().setAttribute("sess","session msg ....");
    request.getServletContext().setAttribute("app","application msg ....");
    return "/user4";
}



    
    Thymeleaf介绍


    

域对象使用

request:




session:



servletContext:


  
效果

Java经典框架之SpringBoot_第62张图片

  
6.2.6 URL表达式



    
    Thymeleaf介绍



    

URL使用

百度
百度

相对路径
相对于服务器的根
相对路径--参数传递
RestFul支持
  

Java经典框架之SpringBoot_第63张图片

  
6.2.7 整合案例改造
我们可以将前面介绍的SpringBoot+MyBatis+Freemaker的案例改为SpringBoot+MyBatis+Thymeleaf的案例,涉及到的页面代码如下



    
    Title


用户管理

添加用户

编号 账号 姓名 邮箱 电话 操作
更新 删除



    
    Title


    




   

二、SpringBoot高级

1.热部署
为了提高我们的开发效率,我们可以放开IDEA中的SpringBoot项目的热部署操作。
  
1.1 放开配置
在IDEA中默认是没有放开热部署操作的,我们需要手动的放开设置。

Java经典框架之SpringBoot_第64张图片

  
1.2 注册
Control+shift+Alt+/ 会出现一个弹出界面。

Java经典框架之SpringBoot_第65张图片

  
然后选择Registry

Java经典框架之SpringBoot_第66张图片

  
1.3 添加devtools


    org.springframework.boot
    spring-boot-devtools
  
2. 异常处理
2.1 自定义错误页面
SpringBoot默认的处理异常的机制:一旦程序出现了异常SpringBoot会想 /error 的url发送请求,在SpringBoot中提供了一个 BasicExceptionController来处理 /error 请求,然后跳转到默认显示异常的页面来展示异常信息。

Java经典框架之SpringBoot_第67张图片

  
如果我们需要将所有的异常统一跳转到我们自定义的错误页面,需要在src/main/resources/template 目录下创建一个 error.html页面,注意名称必须是 error.html。



    
    Title


    

系统出错,请联系管理员....

  

Java经典框架之SpringBoot_第68张图片

  

Java经典框架之SpringBoot_第69张图片

  
2.2 @ExceptionHandle注解
package com.bobo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class UserController {

    @RequestMapping("/show1")
    public String showInfo1(){
        String name = null;
        // 模拟 空指针异常
        name.length();
        return "index";
    }

    @RequestMapping("/show2")
    public String showInfo2(){
        int a = 1/0; // 默认算术异常
        return "index";
    }

    @ExceptionHandler(value = {NullPointerException.class})
    public ModelAndView nullPointerExceptionHandler(Exception e){
        ModelAndView mm = new ModelAndView();
        mm.addObject("error",e.toString());
        mm.setViewName("error1");
        return mm;
    }

    @ExceptionHandler(value = {ArithmeticException.class})
    public ModelAndView arithmeticException(Exception e){
        ModelAndView mm = new ModelAndView();
        mm.addObject("error",e.toString());
        mm.setViewName("error2");
        return mm;
    }
}
  
error1.html



    
    Title


    

系统出错,请联系管理员....nullPointerExceptionHandler

   
error2.html



    
    Title


    

系统出错,请联系管理员....arithmeticException

  
效果

Java经典框架之SpringBoot_第70张图片

  

Java经典框架之SpringBoot_第71张图片

  
2.3 @ControllerAdvice注解
上面的实现将控制器和异常处理的方法写在了一块,显然不太合理,这时我们可以通过@ControllerAdvice注解来实现解耦。
     
专门的异常处理类
package com.bobo.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

// @ControllerAdvice
public class GlobalException {
    //@ExceptionHandler(value = {NullPointerException.class})
    public ModelAndView nullPointerExceptionHandler(Exception e){
        ModelAndView mm = new ModelAndView();
        mm.addObject("error",e.toString());
        mm.setViewName("error1");
        return mm;
    }

    //@ExceptionHandler(value = {ArithmeticException.class})
    public ModelAndView arithmeticException(Exception e){
        ModelAndView mm = new ModelAndView();
        mm.addObject("error",e.toString());
        mm.setViewName("error2");
        return mm;
    }
}
  
控制器代码
package com.bobo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class UserController {

    @RequestMapping("/show1")
    public String showInfo1(){
        String name = null;
        // 模拟 空指针异常
        name.length();
        return "index";
    }
    @RequestMapping("/show2")
    public String showInfo2(){
        int a = 1/0; // 默认算术异常
        return "index";
    }
}
   

Java经典框架之SpringBoot_第72张图片

   
2.4 SimpleMappingExceptionResolver
我们还可以通过SimpleMappingExceptionResolver来简化我们的异常处理。
package com.bobo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.Properties;

@SpringBootApplication
public class SpringbootDemo11Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootDemo11Application.class, args);
    }

    /**
     * 通过SimpleMappingExceptionResolver 设置 特定异常和 处理器的映射关系
     * @return
     */
    // @Bean
    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        properties.put("java.lang.NullPointerException","error1");
        properties.put("java.lang.ArithmeticException","error2");
        resolver.setExceptionMappings(properties);
        return  resolver;
    }
}
   
2.5 HandleExceptionResolver处理
我们上面讲的SimpleMappingExceptionResolver本质上就是实现HandleExceptionResolver的。

Java经典框架之SpringBoot_第73张图片

  
所以我们也可以自己来实现HandleExceptionResolver接口。
package com.bobo.exception;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyHandleExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView mm = new ModelAndView();
        if(e instanceof NullPointerException){
            mm.setViewName("error1");
        }else if(e instanceof  ArithmeticException){
            mm.setViewName("error2");
        }else{
            mm.setViewName("error");
        }
        return mm;
    }
}
   
3. 单元测试
为了提高在开发过程中的效率,我们可以通过SpringBoot中提供的单元测试来快速测试service和dao的业务逻辑。

    org.springframework.boot
    spring-boot-starter-test
    test
    
        
            org.junit.vintage
            junit-vintage-engine
        
    
   
业务逻辑
package com.bobo.service.impl;

import com.bobo.service.IUserService;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

@Service
public class UserServiceImpl implements IUserService {


    @Override
    public List query() {

        return Arrays.asList("张三","李四","王五");
    }
}
     
单元测试
package com.bobo;

import com.bobo.service.IUserService;
import net.bytebuddy.asm.Advice;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SpringbootDemo12ApplicationTests {

    @Autowired
    private IUserService service;


    @Test
    void contextLoads() {
        System.out.println("---->" + service.query());
    }

    @BeforeEach
    void before(){
        System.out.println("before ...");
    }

    @AfterEach
    void after(){
        System.out.println("after ...");
    }

}
  

Java经典框架之SpringBoot_第74张图片

    
4. 整合Shiro
4.1 项目准备
创建一个SpringBoot项目整合MyBatis,Thymeleaf,SpringMVC等并创建相关的配置文件和Service逻辑。
    
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            1.3.2
        
        
            mysql
            mysql-connector-java
        
        
            com.alibaba
            druid
            1.1.8
        
        
        
            org.springframework.boot
            spring-boot-devtools
        
    
  
属性配置文件
server.port=8082

# 配置JDBC的相关信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/logistics?
characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

# 配置连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

# 配置MyBatis的package 设置别名
mybatis.type-aliases-package=com.bobo.pojo

# 指定映射文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml
   
通过MyBatis Generator自动生成持久层的相关的代码(t_user表)或者从之前的货运系统中拷贝对应的代码。

Java经典框架之SpringBoot_第75张图片

  
Service的逻辑实现
package com.bobo.service;

import com.bobo.pojo.User;

import java.util.List;

public interface IUserService {

    public User login(String userName);

    public List query(User user);
}
package com.bobo.service.impl;

import com.bobo.mapper.UserMapper;
import com.bobo.pojo.User;
import com.bobo.pojo.UserExample;
import com.bobo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper mapper;

    @Override
    public User login(String userName) {
        User user =  new User();
        user.setUserName(userName);
        List list = this.query(user);
        if(list != null && list.size() == 1){
            return list.get(0);
        }
        return null;
    }

    @Override
    public List query(User user) {
        UserExample example = new UserExample();
        UserExample.Criteria criteria = example.createCriteria();
        if(user != null){
            if(!"".equals(user.getUserName()) && user.getUserName() != null){
                criteria.andUserNameEqualTo(user.getUserName());
            }
        }
        return mapper.selectByExample(example);
    }
}
  
到此准备完成。
  
4.2 Shiro整合
4.2.1 Shiro的依赖

    org.apache.shiro
    shiro-spring
    1.3.2
   
4.2.2 自定义Realm
package com.bobo.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private IUserService service;

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       return null;
    }
}
  
4.2.3 Shiro的配置
package com.bobo.config;

import com.bobo.realm.MyRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import org.apache.shiro.mgt.SecurityManager;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    /**
     * 配置凭证匹配器
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(1024);
        return matcher;
    }

    /**
     * 注册自定义的Realm
     * @param hashedCredentialsMatcher
     * @return
     */
    @Bean
    public MyRealm myRealm(CredentialsMatcher hashedCredentialsMatcher){
       MyRealm realm = new MyRealm();
       realm.setCredentialsMatcher(hashedCredentialsMatcher);
       return realm;
    }

    /**
     * 注册SecurityManager对象
     * @return
     */
    @Bean
    public SecurityManager securityManager(Realm myRealm){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(myRealm);
        return manager;
    }

    /**
     * 注册ShiroFilterFactoryBean
     * @return
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager manager){
        ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
        filter.setSecurityManager(manager);
        filter.setLoginUrl("/login.do");
        filter.setSuccessUrl("/success.html");
        filter.setUnauthorizedUrl("/refuse.html");
        // 设置过滤器
        Map map = new HashMap<>();
        map.put("/css/**","anon");
        map.put("/img/**","anon");
        map.put("/js/**","anon");
        map.put("/login","anon");
        map.put("/login.do","authc");
        map.put("/**","authc");
        filter.setFilterChainDefinitionMap(map);
        return filter;
    }
}
  
4.2.4 测试
添加对应的测试文件

Java经典框架之SpringBoot_第76张图片

   
package com.bobo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String goLoginPage(){
        return "login";
    }
}
package com.bobo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/query")
    public String query(){
        System.out.println("----user query----");
        return "user";
    }
}
  
4.3 认证实现
4.3.1 自定义Realm
在自定义Realm中完成认证逻辑。
package com.bobo.realm;

import com.bobo.pojo.User;
import com.bobo.service.IUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.SimpleByteSource;
import org.springframework.beans.factory.annotation.Autowired;

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private IUserService service;

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String userName = token.getUsername();
        User user = new User();
        user.setUserName(userName);
        // 账号验证
        user = service.login(userName);
        if(user == null){
            return null;
        }
        return new SimpleAuthenticationInfo(user,user.getPassword(),new SimpleByteSource(user.getU1()) ,"myRealm");
    }

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}
    
4.3.2 控制器
在控制器中完成认证失败的处理。
package com.bobo.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
public class LoginController {

    @RequestMapping("/login")
    public String goLoginPage(){
        return "login";
    }
    
    @RequestMapping("/login.do")
    public String login(HttpServletRequest request){
        Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
        System.out.println("认证错误的信息:" + obj);
        return "/login";
    }

    @RequestMapping("/logout")
    public String logout(){
        SecurityUtils.getSubject().logout();
        return "/login";
    }
}
   
4.3.3 登录页面



    
    Title


    

登录页面

账号:
密码:
   
5. 授权操作
5.1 注解的使用
我们需要开启SpringMVC对注解的支持。
/**
* 开启对Shiro授权注解的支持
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
    AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
    advisor.setSecurityManager(securityManager);
    return advisor;
}
   
在自定义Realm中添加权限。
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    User user = (User) principalCollection.getPrimaryPrincipal();
    System.out.println("获取授权的账号:" + user.getUserName());
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    info.addRole("role1");
    return info;
}
     

Java经典框架之SpringBoot_第77张图片

   

    org.springframework
    spring-aspects
   
启动访问

Java经典框架之SpringBoot_第78张图片

  

Java经典框架之SpringBoot_第79张图片

  

Java经典框架之SpringBoot_第80张图片

  
5.2 标签的使用
添加相关的依赖。

    com.github.theborakompanioni
    thymeleaf-extras-shiro
    2.0.0
  
注入对象
@Bean
public ShiroDialect shiroDialect(){
    return new ShiroDialect();
}
   
在页面中实现处理



    
    Title


    

用户管理

已登录: 用户查询 用户添加 用户修改 用户删除
  
访问效果

Java经典框架之SpringBoot_第81张图片

你可能感兴趣的:(微服务高并发必备技术栈,微服务,java,架构)