淘宝内部优惠券网站怎样做的,杭州网站建设hzyze,柳州网站虚拟主机销售价格,wordpress网易音乐播放器SpringBoot Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. SpringBoot基础 2. Spring…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同时提供RESTfulAPISpringMVC框架用于数据到达服务器后处理请求到数据访问层主要有Hibernate、MyBatis、JPA等持久层框架数据库常用MySQL开发工具推荐IntelliJIDEA。 2. SpringBoot项目构建 SpringBoot项目的构建方式本身是非常简单的实现的方式也有多种。 2.1 手动创建 我们通过基本的Maven项目来手动配置一个SpringBoot。 2.1.1 创建MAVEN项目 创建一个普通的Maven项目即可。 2.1.2 添加依赖 创建一个SpringBoot的Web项目我们需要添加对应的依赖。 ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.bobo/groupIdartifactIdSpringBootDemo01/artifactIdversion1.0-SNAPSHOT/version!-- 1.添加SpringBoot的依赖 --parentartifactIdspring-boot-starter-parent/artifactIdgroupIdorg.springframework.boot/groupIdversion2.3.8.RELEASE/version/parentdependencies!-- 2. 添加SpringMVC的支持 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency/dependencies/project 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 启动程序 执行我们的主方法即可。 访问出现404说明服务启动成功只是请求访问的资源不存在。 2.2 在线构建 我们也可以通过SpringBoot提供的在线地址创建我们的SpringBoot项https://start.spring.io/ 在线生成我们的SpringBoot项目解压后可以直接导入。 2.3 IDEA直接创建 IDEA工具可以直接通过在线创建的工具来直接生成帮助我们简化了下载解压缩的步骤。 到此创建完成。 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 ...;}
}访问即可 为什么能够扫描到这个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}
)}
) 3.2 静态资源 在SpringBoot项目中默认的静态资源【html,css,js,图片....】是放置在resource/static目录中。 效果 3.3 定制Banner 如果我们想要修改服务启动时的那个banner图标我们只需要在resource目录下创建一个banner.txt文件然后将我们要显示的信息写入即可http://patorjk.com/software/taag/#pdisplayfGraffititHELLO 当然我们也可以不显示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); // 关闭掉Bannerapp.run(args);}}3.4 属性文件 在resource目录下的application.properties文件。 3.4.1 默认设置 我们可以通过application.properties文件来修改系统默认的属性比如修改Tomcat相关配置信息。 server.port8082
server.servlet.context-path/springboot 3.4.2 自定义属性 我们可以在application.properties文件中自定义属性供我们在代码中使用。 自定义属性 # 默认属性修改
server.port8082
server.servlet.context-path/springboot
# 自定义属性
user.userNameadmin
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 ...;}
}出现乱码的情况 解决方法 修改了乱码后的效果 3.4.3 yml文件 yml是我们在配置系统属性或者自定义属性的另外一种方式。 user.hello.usernamea
user.hello.password123
user.hello.addresscs
user.hello.age1 改成yml user:hello:username:apassword:123address:csage:1 3.5 日志 SpringBoot中支持 JavaUtil Logging, Log4J, Log4J2和Logback作为日志框架而在SpringBoot中默认支持的是Logback作为日志框架。 简单配置 # 日志配置
#logging.file.pathd:/tools/log
logging.file.named:/tools/log/log.log
logging.level.org.springframework.webDEBUG 引入日志文件的扩展配置文件 ?xml version1.0 encodingUTF-8?
configuration debugfalse!--日志文件主目录这里${user.home}为当前服务器用户主目录--property nameLOG_HOME value${user.home}/log/!--日志文件名称这里spring.application.name表示工程名称--springProperty scopecontext nameAPP_NAME sourcespring.application.name/!--默认配置--include resourceorg/springframework/boot/logging/logback/defaults.xml/!--配置控制台(Console)--include resourceorg/springframework/boot/logging/logback/console-appender.xml/!--配置日志文件(File)--appender nameFILE classch.qos.logback.core.rolling.RollingFileAppender!--设置策略--rollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicy!--日志文件路径这里%d{yyyyMMdd}表示按天分类日志--FileNamePattern${LOG_HOME}/%d{yyyyMMdd}/${APP_NAME}.log/FileNamePattern!--日志保留天数--MaxHistory15/MaxHistory/rollingPolicy!--设置格式--encoder classch.qos.logback.classic.encoder.PatternLayoutEncoder!--格式化输出%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符--pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n/pattern!-- 或者使用默认配置 --!--pattern${FILE_LOG_PATTERN}/pattern--charsetutf8/charset/encoder!--日志文件最大的大小--triggeringPolicy classch.qos.logback.core.rolling.SizeBasedTriggeringPolicyMaxFileSize100MB/MaxFileSize/triggeringPolicy/appender!-- 多环境配置 按照active profile选择分支 --springProfile namedev!--root节点 全局日志级别用来指定最基础的日志输出级别--root levelDEBUGappender-ref refFILE/appender-ref refCONSOLE//root!-- 子节点向上级传递 局部日志级别--logger levelWARN nameorg.springframework/logger levelWARN namecom.netflix/logger levelDEBUG nameorg.hibernate.SQL//springProfilespringProfile nameprod!--root节点 全局日志级别用来指定最基础的日志输出级别--root levelINFOappender-ref refFILE/appender-ref refCONSOLE//root/springProfile
/configuration 引入 3.6 Profile 项目开发中会出现开发环境的切换为了更好的处理我们可以通过Profile来实现之前在Spring的阶段就已经给大家介绍过了Profile但是实现相对复杂了点在SpringBoot中也提供了对Profile的支持而且更加简化创建对应的属性文件。 开发环境 user.host192.168.100.120 生产环境 user.host192.168.111.123 文件名称的命名规则是 application-环境.properties 要让哪个文件生效我们只需要在application.properties文件中指定即可。 测试效果 3.7 静态资源文件 在SpringBoot项目中默认的存放路径是在static目录下但是实际开发的时候有可能我们需要调整资源的目录。 在main目录下创建一个webapp目录 设置类型为 ResourceRoot。 可以直接访问 自定义目录 有些情况下我们需要将特定的目录作为我们存放静态资源文件的目录。 ## 设置自定义的路径
spring.mvc.static-path-pattern/**
## 覆盖掉默认的配置录
spring.resources.static-locationsclasspath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,class path:/sfile/ 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(namefirstServlet,urlPatterns /first)
public class FirstServlet extends HttpServlet {Overrideprotected 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 {Overrideprotected 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);}Beanpublic ServletRegistrationBean servletRegistrationBean(){ServletRegistrationBean bean new ServletRegistrationBean(new SecondServlet());bean.addUrlMappings(/second);return bean;}
} 测试 3.8.2 Filter 第一种方式 创建过滤器 WebFilter(urlPatterns /first)
public class FirstFilter implements Filter {Overridepublic 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);}
} 在启动器中添加注解。 测试 第二种方式 在该过滤器中我们不用添加对应的注解。 package com.bobo.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;public class SecondFilter implements Filter {Overridepublic 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);}
}启动器中注入 注册器。 Beanpublic FilterRegistrationBean filterRegistrationBean(){FilterRegistrationBean bean new FilterRegistrationBean(new SecondFilter());bean.addUrlPatterns(/second);return bean;} 测试 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 {Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println(FirstListener ... 初始化);}Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println(FirstListener ... 销毁);}
}启动器中注解 测试效果 第二种方式 package com.bobo.listener;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;public class SecondListener implements ServletContextListener {Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println(SecondListener ... 初始化);}Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println(SecondListener ... 销毁);}
}Beanpublic ServletListenerRegistrationBean servletListenerRegistrationBean(){return new ServletListenerRegistrationBean(new SecondListener());} 测试 3.9 文件上传 3.9.1 表单页面 !DOCTYPE html
html langen
headmeta charsetUTF-8title用户管理/title
/head
bodyh1文件上传案例:/h1form action/user/upload methodpost enctypemultipart/form-data label账号:/labelinput typetext nameusernamebrlabel头像:/labelinput typefile nameuploadbrinput typesubmit value提交/form
/body
/html 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.port8082spring.servlet.multipart.enabledtrue
# 设置单个文件上传的大小
spring.servlet.multipart.max-file-size20MB
# 设置一次请求上传文件的总的大小
spring.servlet.multipart.max-request-size200MB 3.9.4 测试 上传成功的文件 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 添加依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-freemarker/artifactId
/dependency 4.2.2 配置 我们在属性文件中设置视图解析器的前后缀。 spring.freemarker.suffix.ftl 4.2.3 创建Freemaker文件 然后我们在系统的模板文件中创建Freemaker文件注意该文件为一个后缀为 .ftl 的文件。 htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbodyh1Hello Freemark .../h1/body
/html 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 测试 直接启动服务访问看效果。 这就表示整合成功了。 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表达式直接取出来。 htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbodyh1Hello Freemark .../h1${userName}br${age}br/body
/html boolean不能直接转换为string类型。 这时我们要通过内部的转换函数来处理。 htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbodyh1Hello Freemark .../h1${userName}br${age}br${address}br${flag?string(真,假)}br/body
/html htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbodyh1Hello Freemark .../h1${userName}br${age}br${address}br${flag?string(真,假)}br${birth}br/body
/html 时间类型也需要转换。 htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbodyh1Hello Freemark .../h1${userName}br${age}br${address}br${flag?string(真,假)}br${birth?string(yyyy-MM-dd)}br/body
/html 4.3.2 单个数据处理 我们服务端绑定的单个数据比如字符串或者数字我们可能需要对这些数据做出调整比如数字要四舍五入字符串我们需要截取等操作。 htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbodyh1Hello Freemark .../h1${userName}br${age}br${address}br${flag?string(真,假)}br${birth?string(yyyy-MM-dd)}brhr#-- 注释符 --#assign x3.1415#assign y6!--mN:小数部分最小N位MN:小数部分最大N位--x${x}bry${y}br#{x;M2}br!-- 3.14 --#{x;m2}br!-- 3.14 --#{y;M2}br!-- 6 --#{y;m2}br!-- 6.00 --body
/html 字符串拼接处理 #assign hellohello freemarker
#-- 字符串拼接 --
HELLO-${hello}br
#-- EL表达式中的常量表示 --
${HELLO|hello}br
#-- 常量中使用数据 --
${HELLO*${hello}}br
${userName}----${hello}br
${userName-- hello}br 字符串截取 ${hello}br
${hello[1]}br
${hello[4]}br
${hello[1..6]}br
${hello[3..]}br 4.3.3 自定义对象 RequestMapping(/query1)
public String query1(Model model){User user new User(666,admin,123456);model.addAttribute(user,user);return user1;
} htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbody#-- 自定义对象 --${user.id}br-- #--${user[id]}br--${user.userName}br--${user[userName]}br${user.password}br/body
/html 4.3.4 集合对象 RequestMapping(/query1)public String query1(Model model){User user new User(666,admin,123456);model.addAttribute(user,user);MapString,Object 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;} 4.3.5 算数运算 算数运算包含基本的四则运算和求模运算运算符有 加法
减法 -
乘法 *
除法 /
求模 (求余) % htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbodyh1算术运算符/h1br${99100*30}br${99/7}br${(99/7)?int}br${55%3}br/body
/html 4.3.6 比较运算符 4.3.7 逻辑操作 常用的逻辑操作符 逻辑 或 ||
逻辑 与
逻辑 非 ! 逻辑操作符仅仅在布尔值之间有效若用在其他类型将会产生错误导致模板执行中止。 4.3.8 内置函数 内建函数就像FreeMarker在对象中添加的方法一样。 要防止和实际方法和其它子变量的命名冲突则不能使用点 (.)这里使用问号 (?)来和父对象分隔开。 比如想要保证 path 有起始的 / 那么可以这么来写 path?ensure_starts_with(’/’)。 path 后的Java对象(通常就是 String) 并没有这样的方法这是FreeMarker添加的。为了简洁如果方法没有参数 那么就可以忽略 ()比如想要获取 path 的长度就可以写作path?length 而不是 path?length()。 更多内置函数见此http://freemarker.foofun.cn/ref_builtins.html htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbodyh1算术运算符/h1br${99100*30}br${99/7}br${(99/7)?int}br${55%3}brh1内建函数:/h1#assign helloHello FreeMarker#assign pagespan stylecolor:redHELLO/span${hello}br${page}br${page?html}br${hello?upper_case}br${hello?lower_case}br${now?date}br${now?datetime}br${now?time}br/body
/html 4.3.9 分支和循环 if语句switch语句已经循环语句基本的语法格式和我们在Java中使用的是一样的。我们只需要注意下在具体的使用格式上。 htmlheadtitleFreemaker/titlemeta charsetUTF-8/headbodyh1算术运算符/h1br${99100*30}br${99/7}br${(99/7)?int}br${55%3}brh1内建函数:/h1#assign helloHello FreeMarker#assign pagespan stylecolor:redHELLO/span${hello}br${page}br${page?html}br${hello?upper_case}br${hello?lower_case}br${now?date}br${now?datetime}br${now?time}brhr#assign age 18 #if age 18等于18#elseif age gt 18 大于18#else 小于18/#ifnull的判断:br#assign mypagea#-- ?? 检测值是否存在 --#if mypage??mypage存在#else mypage不存在/#ifbr#assign i3#switch i#case 1ok#break #case 2ok2#break #case 3ok3#break #default ok4/#switch#list list as obj#if obj李四#break /#if${obj}br/#list#assign aaa555#-- !的使用--br${aaa!666}!-- 如果aaa存在就显示aaa本来的值如果aaa不存在就显示666 --br/body
/html 5.综合案例 前面介绍了Freemaker这节介绍SpringBoot整合MyBatis同时结合Freemaker展现数据。 5.1 项目创建 添加相关的依赖 ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.3.9.RELEASE/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.bobo/groupIdartifactIdspringboot-demo09/artifactIdversion0.0.1-SNAPSHOT/versionnamespringboot-demo09/namedescriptionDemo project for Spring Boot/descriptionpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-freemarker/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scopeexclusionsexclusiongroupIdorg.junit.vintage/groupIdartifactIdjunit-vintage-engine/artifactId/exclusion/exclusions/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion1.3.2/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.0.14/version/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project添加相关的配置文件 server.port8082# 配置JDBC的相关信息
spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver
spring.datasource.urljdbc:mysql://localhost:3306/logistics?
characterEncodingutf-8serverTimezoneUTC
spring.datasource.usernameroot
spring.datasource.password123456# 配置连接池
spring.datasource.typecom.alibaba.druid.pool.DruidDataSource# 配置MyBatis的package 设置别名
mybatis.type-aliases-packagecom.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 {ListUser query();}创建映射文件。 ?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.bobo.mapper.UserMapperselect idquery resultTypeuserselect * from t_user/select
/mapper 属性文件中添加Mapper映射文件的路径。 创建Service package com.bobo.service;import com.bobo.pojo.User;import java.util.List;public interface IUserService {ListUser 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 {Autowiredprivate UserMapper mapper;Overridepublic ListUser 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 {Autowiredprivate IUserService service;RequestMapping(/query)public String query(Model model){ListUser list service.query();model.addAttribute(list,list);return /user;}}属性文件中配置Freemaker的后缀。 创建Freemaker模板文件并且展示数据。 htmlheadtitle用户管理/titlemeta charsetUTF-8/headbodyh1用户管理/h1tabletrth编号/thth账号/thth姓名/thth邮箱/thth电话/thth操作/th/tr#list list as usertrtd${user.user_id}/tdtd${user.user_name}/tdtd${user.real_name!}/tdtd${user.email!}/tdtd${user.phone!}/tdtd.../td/tr/#list/table/body
/html 启动操作之前我们需要添加 MyBatis接口的扫描路径。 访问测试 5.3 添加用户 htmlheadtitle用户管理/titlemeta charsetUTF-8/headbodyh1用户管理/h1form action/user/userUpdate methodpost input typehidden nameuser_id value${user.user_id}label账号/labelinput typetext nameuser_name value${user.user_name}brlabel姓名/labelinput typetext namereal_name value${user.real_name!}brlabel邮箱/labelinput typetext nameemail value${user.email!}brlabel电话/labelinput typetext namephone value${user.phone!}brinput typesubmit value提交/form/body
/html 5.4 更新用户 htmlheadtitle用户管理/titlemeta charsetUTF-8/headbodyh1用户管理/h1form action/user/userUpdate methodpost input typehidden nameuser_id value${user.user_id}label账号/labelinput typetext nameuser_namevalue${user.user_name}brlabel姓名/labelinput typetext namereal_namevalue${user.real_name!}brlabel邮箱/labelinput typetext nameemailvalue${user.email!}brlabel电话/labelinput typetext namephonevalue${user.phone!}brinput typesubmit value提交/form/body
/html 5.5 删除用户 htmlheadtitle用户管理/titlemeta charsetUTF-8/headbodyh1用户管理/h1h2a href/user/dispatchUpdate添加用户/a/h2tabletrth编号/thth账号/thth姓名/thth邮箱/thth电话/thth操作/th/tr#list list as usertrtd${user.user_id}/tdtd${user.user_name}/tdtd${user.real_name!}/tdtd${user.email!}/tdtd${user.phone!}/tdtda href/user/dispatchUpdate?id${user.user_id}更新/aa href/user/deleteUser?id${user.user_id}删除/a/td/tr/#list/table/body
/html 6. Thymeleaf Thymeleaf是SpringBoot中推荐使用的前端模板框架。所以比较重要。 6.1 SpringBoot整合 创建一个SpringBoot项目然后添加对应的依赖。 ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.3.9.RELEASE/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.bobo/groupIdartifactIdspringboot-demo10/artifactIdversion0.0.1-SNAPSHOT/versionnamespringboot-demo10/namedescriptionDemo project for Spring Boot/descriptionpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId/dependency!-- 使用Thymeleaf需要添加的依赖 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scopeexclusionsexclusiongroupIdorg.junit.vintage/groupIdartifactIdjunit-vintage-engine/artifactId/exclusion/exclusions/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project创建Thymeleaf文件Thymeleaf的后缀就是html我在template目录下直接创建一个html页面即可但是为了能够使用Thymeleaf中的标签提示我们添加对应的xmlns即可。 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleThymeleaf介绍/title
/head
bodyh1Hello Thymeleaf/h1/body
/html 添加跳转的控制器。 Controller
public class UserController {RequestMapping(/hello)public String hello(){System.out.println(hello ....);return /user;}
} 启动服务测试 访问成功说明整合搞定。 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;
} 模板文件 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleThymeleaf介绍/title
/head
bodyh1Hello Thymeleaf/h1label th:texthello/labelbrlabel th:text${hello}/labelbrlabel th:text${now}/labelbrlabel th:text${flag}/labelbrlabel th:text${age}/labelbrh2th:value的使用/h2input typetext valueaaabrinput typetext th:value${msg}br
/body
/html 显示效果 6.2.2 内置函数 我们通过上面的案例发现显示Model中的数据很方便但是显示的数据的格式可能不满足我们的需求这时我们需要调整就需要借助内置的函数来帮助我们实现我们主要介绍字符串和时间相关的函数。 注意点 1. 调用内置函数对象一定要使用# 2. 大部分的内置函数都以 s 结尾 比如 strings numbers dates 字符串的处理 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleThymeleaf介绍/title
/head
bodyh1string类型介绍/h1hello:span th:text${hello}/spanbrhello是否为空:span th:text${#strings.isEmpty(hello)}/spanbrhello字符串是否包含th:span th:text${#strings.contains(hello,th)}
/spanbrhello字符串是否包含Th:span th:text${#strings.contains(hello,Th)}
/spanbrhello以H开头span th:text${#strings.startsWith(hello,H)}/spanbrhello以a开头span th:text${#strings.startsWith(hello,a)}/spanbrhello以H结尾span th:text${#strings.endsWith(hello,H)}/spanbrhello以a结尾span th:text${#strings.endsWith(hello,a)}/spanbrhello的长度:span th:text${#strings.length(hello)}/spanbrhello都大写:span th:text${#strings.toUpperCase(hello)}/spanbrhello都小写:span th:text${#strings.toLowerCase(hello)}/spanbr
/body
/html 日期时间类型的处理 h1日期时间处理/h1
时间:span th:text${now}/spanbr
时间:span th:text${#dates.format(now)}/spanbr
时间:span th:text${#dates.format(now,yy/MM/dd)}/spanbr
时间:span th:text${#dates.format(now,yy/MM/dd hh:ss:mm)}/spanbr
时间:span th:text${#dates.format(now,yy/MM/dd HH:ss:mm)}/spanbr
年份:span th:text${#dates.year(now)}/spanbr
月份:span th:text${#dates.month(now)}/spanbr
日期:span th:text${#dates.day(now)}/spanbr
本周的第几天span th:text${#dates.dayOfWeek(now)}/spanbr
小时:span th:text${#dates.hour(now)}/spanbr 6.2.3 条件判断 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleThymeleaf介绍/title
/head
bodyh1条件判断/h1h2if语句/h2span th:if${sex} 男男/spanspan th:unless${sex} 男女/spanbr!-- and or not --span th:if${flag or false}or的使用11/spanspan th:unless${flag or false}or的使用12/spanbrspan th:if${flag and false}and的使用21/spanspan th:unless${flag and false}and的使用22/spanbrspan th:if${not flag}not的使用11/spanspan th:unless${not flag}not的使用22/spanbr!-- 三木运算符 --span th:texttrue?A:B/spanbr!-- switch语句 --hrdiv th:switch${age}div th:case1717岁/divdiv th:case1818岁/divdiv th:case1919岁/divdiv th:case*其他.../div/div
/body
/html 6.2.4 循环语句 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleThymeleaf介绍/title
/head
bodyh1循环判断/h1div th:eachc : ${list1}span th:text${c}/spanbr/divhrdiv th:eachuser : ${list2}span th:text${user.id}/spannbsp;nbsp;span th:text${user.userName}/spannbsp;nbsp;span th:text${user.address}/spanbr/divhrdiv th:eachm : ${map}!-- 每次循环获取的是一个KV对 --span th:text${m.getKey() : m.getValue().getId()}/spanspan th:text${m.getKey() : m.getValue().getUserName()}/spanspan th:text${m.getKey() : m.getValue().getAddress()}/span/divhrdiv th:eachuser,iter : ${list2}span th:text${iter.count}/spannbsp;nbsp;span th:text${iter.index}/spannbsp;nbsp;span th:text${user.id}/spannbsp;nbsp;span th:text${user.userName}/spannbsp;nbsp;span th:text${user.address}/spanbr/div
/body
/html 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;
} !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleThymeleaf介绍/title
/head
bodyh1域对象使用/h1h2request:/h2span th:text${#httpServletRequest.getAttribute(req)}/spanbrspan th:text${#request.getAttribute(req)}/spanbrspan th:text${req}/spanbrh2session:/h2span th:text${#httpSession.getAttribute(sess)}/spanbrspan th:text${#session.getAttribute(sess)}/spanbrh2servletContext:/h2span th:text${#servletContext.getAttribute(app)}/spanbr
/body
/html 效果 6.2.6 URL表达式 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleThymeleaf介绍/title
/head
bodyh1URL使用/h1a hrefhttp://www.baidu.com百度/abra th:href{http://www.baidu.com}百度/abrhra th:href{/show}相对路径/abra th:href{~/project2/app1}相对于服务器的根/abra th:href{/show(id1,nameaaa)}相对路径--参数传递/abra th:href{/path/{id}/show(id66,name123)}RestFul支持/a
/body
/html 6.2.7 整合案例改造 我们可以将前面介绍的SpringBootMyBatisFreemaker的案例改为SpringBootMyBatisThymeleaf的案例涉及到的页面代码如下 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleTitle/title
/head
body
h1用户管理/h1
h2a th:href{/user/dispatchUpdate}添加用户/a
/h2tabletrth编号/thth账号/thth姓名/thth邮箱/thth电话/thth操作/th/trtr th:eachuser : ${list}td th:text${user.user_id}/tdtd th:text${user.user_name}/tdtd th:text${user.real_name}/tdtd th:text${user.email}/tdtd th:text${user.phone}/tdtda th:href{/user/dispatchUpdate(id${user.user_id})}更新/aa th:href{/user/deleteUser(id${user.user_id})}删除/a/td/tr/table
/body
/html !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleTitle/title
/head
bodyform th:action{/user/userUpdate} methodpost span th:if${user}input typehidden nameuser_id th:value${user.user_id}/spanlabel账号/labelinput typetext nameuser_name th:value${ usernull ?:user.user_name}brlabel姓名/labelinput typetext namereal_name th:value${usernull ?:user.real_name}brlabel邮箱/labelinput typetext nameemail th:value${usernull ?:user.email}brlabel电话/labelinput typetext namephone th:value${usernull ?:user.phone}brinput typesubmit value提交/form
/body
/html 二、SpringBoot高级 1.热部署 为了提高我们的开发效率我们可以放开IDEA中的SpringBoot项目的热部署操作。 1.1 放开配置 在IDEA中默认是没有放开热部署操作的我们需要手动的放开设置。 1.2 注册 ControlshiftAlt/ 会出现一个弹出界面。 然后选择Registry 1.3 添加devtools !--devtools 热部署的支持 --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactId
/dependency 2. 异常处理 2.1 自定义错误页面 SpringBoot默认的处理异常的机制一旦程序出现了异常SpringBoot会想 /error 的url发送请求在SpringBoot中提供了一个 BasicExceptionController来处理 /error 请求然后跳转到默认显示异常的页面来展示异常信息。 如果我们需要将所有的异常统一跳转到我们自定义的错误页面需要在src/main/resources/template 目录下创建一个 error.html页面注意名称必须是 error.html。 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleTitle/title
/head
bodyh1系统出错请联系管理员..../h1span th:text${exception}/span
/body
/html 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 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleTitle/title
/head
bodyh1系统出错请联系管理员....nullPointerExceptionHandler/h1span th:text${error}/span
/body
/html error2.html !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleTitle/title
/head
bodyh1系统出错请联系管理员....arithmeticException/h1span th:text${error}/span
/body
/html 效果 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;}
}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*/// Beanpublic 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的。 所以我们也可以自己来实现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 {Overridepublic 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的业务逻辑。 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scopeexclusionsexclusiongroupIdorg.junit.vintage/groupIdartifactIdjunit-vintage-engine/artifactId/exclusion/exclusions
/dependency 业务逻辑 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 {Overridepublic ListString 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 {Autowiredprivate IUserService service;Testvoid contextLoads() {System.out.println(---- service.query());}BeforeEachvoid before(){System.out.println(before ...);}AfterEachvoid after(){System.out.println(after ...);}}4. 整合Shiro 4.1 项目准备 创建一个SpringBoot项目整合MyBatisThymeleafSpringMVC等并创建相关的配置文件和Service逻辑。 dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scopeexclusionsexclusiongroupIdorg.junit.vintage/groupIdartifactIdjunit-vintage-engine/artifactId/exclusion/exclusions/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion1.3.2/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.8/version/dependency!--devtools 热部署的支持 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactId/dependencydependencies 属性配置文件 server.port8082# 配置JDBC的相关信息
spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver
spring.datasource.urljdbc:mysql://localhost:3306/logistics?
characterEncodingutf-8serverTimezoneUTC
spring.datasource.usernameroot
spring.datasource.password123456# 配置连接池
spring.datasource.typecom.alibaba.druid.pool.DruidDataSource# 配置MyBatis的package 设置别名
mybatis.type-aliases-packagecom.bobo.pojo# 指定映射文件的位置
mybatis.mapper-locationsclasspath:mapper/*.xml 通过MyBatis Generator自动生成持久层的相关的代码(t_user表)或者从之前的货运系统中拷贝对应的代码。 Service的逻辑实现 package com.bobo.service;import com.bobo.pojo.User;import java.util.List;public interface IUserService {public User login(String userName);public ListUser 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 {Autowiredprivate UserMapper mapper;Overridepublic User login(String userName) {User user new User();user.setUserName(userName);ListUser list this.query(user);if(list ! null list.size() 1){return list.get(0);}return null;}Overridepublic ListUser 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的依赖 dependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-spring/artifactIdversion1.3.2/version
/dependency 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 {Autowiredprivate IUserService service;/*** 认证* param authenticationToken* return* throws AuthenticationException*/Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {return null;}/*** 授权* param principalCollection* return*/Overrideprotected 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*/Beanpublic HashedCredentialsMatcher hashedCredentialsMatcher(){HashedCredentialsMatcher matcher new HashedCredentialsMatcher();matcher.setHashAlgorithmName(md5);matcher.setHashIterations(1024);return matcher;}/*** 注册自定义的Realm* param hashedCredentialsMatcher* return*/Beanpublic MyRealm myRealm(CredentialsMatcher hashedCredentialsMatcher){MyRealm realm new MyRealm();realm.setCredentialsMatcher(hashedCredentialsMatcher);return realm;}/*** 注册SecurityManager对象* return*/Beanpublic 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);// 设置过滤器MapString,String 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 测试 添加对应的测试文件 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 {Autowiredprivate IUserService service;/*** 认证* param authenticationToken* return* throws AuthenticationException*/Overrideprotected 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*/Overrideprotected 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 登录页面 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8titleTitle/title
/head
bodyh1登录页面/h1form th:action{/login.do} methodpost账号:input typetext nameusername th:valueadmin1br密码:input typepassword namepassword th:value123brinput typesubmit value提交/form
/body
/html 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;
} dependencygroupIdorg.springframework/groupIdartifactIdspring-aspects/artifactId
/dependency 启动访问 5.2 标签的使用 添加相关的依赖。 dependencygroupIdcom.github.theborakompanioni/groupIdartifactIdthymeleaf-extras-shiro/artifactIdversion2.0.0/version
/dependency 注入对象 Bean
public ShiroDialect shiroDialect(){return new ShiroDialect();
} 在页面中实现处理 !DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.orgxmlns:shirohttp://www.pollix.at/thymeleaf/shiro
headmeta charsetUTF-8titleTitle/title
/head
bodyh1用户管理/h1shiro:authenticated已登录:shiro:principal propertyuserName/shiro:principal/shiro:authenticateda href# shiro:hasRolerole1用户查询/aa href# shiro:hasRolerole1用户添加/aa href# shiro:hasRolerole2用户修改/aa href# shiro:hasRolerole2用户删除/a
/body
/html 访问效果