赞
踩
SpringBoot2讲义链接 源码链接 springboot中文网
由于讲义中有代码的详细实现步骤,故此笔记只记录理论部分,项目具体构建细节需搭配 讲义 食用
项目见讲义第1章,项目名为 001-springboot-pre Xml 配置容器(用maven但没有用模板)
为什么要使用 Spring Boot
因为Spring, SpringMVC 需要使用的大量的配置文件 (xml文件)
还需要配置各种对象,把使用的对象放入到spring容器中才能使用对象
需要了解其他框架配置规则。
SpringBoot 就相当于 不需要配置文件的Spring+SpringMVC。 常用的框架和第三方库都已经配置好了。
拿来就可以使用了。
SpringBoot开发效率高,使用方便多了
JavaConfig: 使用java类作为xml配置文件的替代, 是配置spring容器的纯java的方式。 在这个java类这可以创建java对象,把对象放入spring容器中(注入到容器)
一般用来导入第三方Bean,函数的返回值设置为第三方Bean对象即可
要完成以上功能,需要使用以下两个注解:
@Configuration: 放在一个类的上面,表示这个类是作为配置文件使用的。相当于xml
@Bean:声明对象,把对象注入到容器中。
例子:
// 先创建Student实体类 package com.bjpowernode.config; /** * Configuration:表示当前类是作为配置文件使用的。 就是用来配置容器的 * 位置:在类的上面 * * SpringConfig这个类就相当于 applicationContext.xml * 没有xml 配置文件,使用 java 类代替 xml 配置文件 的作用。通过@Configuration表示当前类是作为配置 *文件使用的 */ @Configuration // configuration 配置 public class SpringConfig { /** * 创建方法,方法的返回值是对象。 在方法的上面加入@Bean * 方法的返回值对象就注入到容器中。 * * @Bean: 把对象注入到spring容器中。 作用相当于在applicationContext.xml中配置 <bean></bean> * * 位置:方法的上面 * * 说明:@Bean,不指定对象的名称,默认对象名称是方法名。 即<bean>中id属性的值 * */ @Bean public Student createStudent(){ Student s1 = new Student(); s1.setName("张三"); s1.setAge(26); s1.setSex("男"); return s1; } /*** * 指定对象在容器中的名称(指定<bean>的id属性) * @Bean的name属性,指定对象的名称(id) */ @Bean(name = "lisiStudent") public Student makeStudent(){ Student s2 = new Student(); s2.setName("李四"); s2.setAge(22); s2.setSex("男"); return s2; } } /* 传统方式: 1.创建实体类 2.在resources目录下创建applicationContext.xml文件 3.在applicationContext.xml文件中配置bean的信息 */
测试类:
// 如果使用xml配置文件的方式,要使用 ClassPathXmlApplicationContext("applicationContext.xml")读取配置文件,创建容器对象并注入Bean
// 如果使用javaConfig的方式,要使用 AnnotationConfigApplicationContext(javaConfig.class)读取配置类中的信息,创建容器对象并注入Bean
ApplicationContext ctx = new
AnnotationConfigApplicationContext(SpringConfig.class);
ctx.getBean("xxx"); // 获取容器中的对象
@ImportResource 作用:导入其他的xml配置文件, 等于 在xml 中进行如下操作:
<import resources="其他配置文件"/>
前面学过在applicationContext_service.xml 中 导入 applicationContext_mapper.xml文件
应用场景:要使用JavaConfig,同时要使用xml配置文件中的信息。在JavaConfig类中导入xml文件中的配置信息
若xml文件和javaConfig类中创建了同名的Bean,且配置类中使用了@ImportResource,则优先使用xml文件中配置的Bean对象的信息
例如:
// applicationContext.xml,beans.xml都放在resources目录下
@Configuration
@ImportResource(value ={ "classpath:applicationContext.xml","classpath:beans.xml"})
public class SpringConfig {
}
这样的话, resources目录下applicationContext.xml,beans.xml这些文件中配置的Bean也会被装载到容器中。
@PropertyResource: 读取properties属性配置文件。
使用属性配置文件可以实现外部化配置 ,在程序代码之外提供数据。
步骤:
在resources目录下,创建properties文件, 使用k=v的格式提供数据
在配置类上使用 @PropertyResource 指定properties文件的位置,使用@ComponentScan创建实体类对象实例
实体类用@Component标识,变量上使用@Value(value=“${key}”)获取properties文件中的数据
使用@Value这种方式,实体类中使用@Component创建对象,@Value赋值。无需提供get/set方法。
在spring笔记中第6节项目4中有所提及
@Configuration // JavaConfig
@ImportResource(value ={ "classpath:applicationContext.xml"})
@PropertySource(value = "classpath:config.properties") //资源文件指定
@ComponentScan(basePackages = "com.bjpowernode.vo") //组件扫描器,扫描@Component所标注的类,并创建该类的对象实例
public class SpringConfig {
}
相当于在xml中配置如下信息:
<context:property-placeholder location="classpath:config.properties"/>
<context:component-scan base-package="com.bjpowernode.vo" />
<import resource="classpath:applicationContext.xml"/>
个人理解:将properties配置文件的信息都保存在实体类中,由于实体类上有@Componen注解,当 包扫描器(ComponentScan)扫到该类时,会创建该实体类对象的实例,并放到容器中。故这样能得到配置文件中的信息
中文乱码:
若依然中文乱码,则需要在设置编码之后,重新编写 properties文件
SpringBoot是Spring中的一个成员, 可以简化Spring,SpringMVC的使用。 他的核心还是IOC容器。
特点:
Create stand-alone Spring applications
创建spring应用
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
内嵌的tomcat, jetty , Undertow
Provide opinionated ‘starter’ dependencies to simplify your build configuration
提供了starter起步依赖,简化应用的配置。
比如使用MyBatis框架 , 需要在Spring项目中,配置MyBatis的对象 SqlSessionFactory , Dao的代理对象
在SpringBoot项目中,只需要在pom.xml里面,加入一个 mybatis-spring-boot-starter依赖
Automatically configure Spring and 3rd party libraries whenever possible
尽可能去配置spring和第三方库。叫做自动配置(就是把spring中的,第三方库中的对象都创建好,放到容器中, 开发人员可以直接使用)
Provide production-ready features such as metrics, health checks, and externalized configuration
提供了健康检查, 统计,外部化配置
Absolutely no code generation and no requirement for XML configuration
不用生成代码, 不用使用xml,做配置
项目见讲义第1.2.1 - 1.2.3章,项目名 002 - 004
使用Spring提供的初始化器, 就是向导创建SpringBoot应用 【见讲义1.2节】
使用的地址: https://start.spring.io
SpringBoot项目的结构:
使用国内的地址
https://start.springboot.io
见讲义(就是直接导入坐标而已)
新版本idea只有springBoot3的创建,最低jdk版本支持也变成了jdk17。为了使用springBoot2.4.2,将https://start.spring.io/
或者http://start.springboot.io/
替换为 https://start.aliyun.com/
目前只添加了 Spring Web的依赖
注意:使用这种方式,它会在单独的一个包下为我们创建主启动类,我们将主启动类放到上一级目录下。因为该级目录下以后会有子包,对应着我们的三层架构,这样做的目的是为了运行主启动类时,扫描该类所在的包和所有子包
项目005:由于springBoot内嵌了tomcat,所以可以直接通过请求访问资源
<!--web的起步依赖(实现mvc的功能)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
有了该依赖就能够接收和响应请求了
在com.zjs.controller包下创建处理请求的类
@Controller // 控制器对象
public class HelloSpringBoot {
@RequestMapping("/hello")
@ResponseBody // 返回json字符串
public String hello() {
return "hello, springboot";
}
}
在com.zjs包下有一个主启动类,点击运行
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
在浏览器地址栏是输入 http://localhost:8080/hello。因为没有在配置文件中指定项目名,所以可以这样写
@SpringBootApplication是一个复合注解:由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三者组成
@SpringBootApplication:Springboot应用标注在某个类上,说明是Springboot的自动配置类。springboot运行这个类的main方法启动sprigboot的应用
@SpringBootConfiguration
@Configuration // JavaCofig:可声明对象<bean>
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@EnableAutoConfiguration
@ComponentScan
@ComponentScan 组件扫描器,找到注解,根据注解的功能创建对象,给属性赋值等等。
默认扫描的包: @ComponentScan所在的类所在的包和子包。
项目见讲义第1.2.4章,项目名为 006)
Spring Boot 的核心配置文件用于配置 Spring Boot 程序,名字必须以 application 开始
扩展名有: properties( k=v) ; yml ( k: v,:后有空格)
使用application.properties, application.yml 【目前推崇用 yml后缀】
同名配置文件(properties 和 yml),默认使用的是 properties格式的配置文件
例1:application.properties设置 端口和上下文
#设置端口号
server.port=8082
#设置访问应用上下文路径, contextpath
server.servlet.context-path=/myboot
访问路径:http://localhost:8082/myboot/hello
例2: application.yml
server:
port: 8083
servlet:
context-path: /myboot2
访问路径:http://localhost:8083/myboot2/hello
项目见讲义第1.2.4.3章,项目名为 007)
有开发环境, 测试环境, 上线的环境。
每个环境有不同的配置信息, 例如端口, 上下文件, 数据库url,用户名,密码等等
使用多环境配置文件,可以方便的切换不同的配置。
使用方式: 创建多个配置文件, 名称规则: application-环境名称.properties(yml)
配置文件是普通的文件,通过 new File创建即可,要加后缀
创建开发环境的配置文件: application-dev.properties( application-dev.yml )
创建测试者使用的配置: application-test.properties
在application.properties中指定使用哪一个配置:
# 指定使用 开发环境的配置文件
spring.profiles.active=dev // profiles 配置
项目见讲义第1.2.4.4.2 章,项目名为 008
@Value在本笔记第 1.3节中讲过,在讲义 第1.2.4.4.1章也讲了
- @Value(“${key}”) , key 来自 application.properties(yml)
- @Value 不仅用于实体类,也可以用于控制器对象,通过在控制器对象的成员变量上加@Value注解获取配置文件中的值
@ConfigurationProperties: 把配置文件的数据映射为java对象。 用于自定义配置项比较多的情况
属性:prefix,是application.properties配置文件中的某些key的开头的内容。
如果配置文件中的key没有前缀,则 必须设置前缀
Java对象:
@Component
@ConfigurationProperties(prefix = "school")
public class SchoolInfo {
private String name;
private String website;
private String address;
// get、set、toString
}
application.properties
#配置端口号
server.port=8082
#context-path
server.servlet.context-path=/myboot
#自定义key=value
school.name=动力节点
school.website=www.bjpowernode.com
school.address=北京的大兴区
site=www.bjpowernode.com
控制器:
@Controller
@ResponseBody // @RestController相当于上述俩个注解的作用
public class SchoolController {
@Resource // 自动注入
private SchoolInfo schoolInfo;
@RequestMapping("/school")
public String doSchool(){
return "学校信息:"+schoolInfo.toString();
}
}
前端请求:http://localhost:8082:/myboot/school
项目见讲义第1.2.5章,项目名为 009
SpringBoot不推荐使用jsp ,而是使用模板技术代替jsp(第9章)
使用jsp需要配置:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
如果需要使用servlet, jsp,jstl的功能,还需要加入以下依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
没有指定版本的,使用springboot默认配置的版本(标签中的中指定的版本)
指定版本的,使用指定版本。
创建一个存放jsp的目录,一般叫做webapp(src/main/webapp),在该目录下创建jsp文件
如果在webapp目录上右键,没有创建jsp的选项,可以在Project Structure中指定webapp目录,为 Web Resource Directory
创建Controller, 跳转到上述 jsp文件(使用的是视图的逻辑名称【不是全路径名,而是文件名,具体见MVC笔记】,要配置视图解析器)
在application.propertis文件中配置视图解析器
#配置 SpringMVC 的视图解析器
#其中:前缀 / 相当于 src/main/webapp 目录
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
需要在pom.xml的 标签中指定jsp文件编译后的存放目录: META-INF/resources
<resources>
<resource>
<!--jsp源文件位置-->
<directory>src/main/webapp</directry>
<!--指定编译到META-INF/resource,该目录不能随便写-->
<targetPath>META-INF/resources</targetPath>
<!--指定要把哪些文件编译进去,**表示 webapp 目录及子目录,*.*表示所有文件-->
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
项目见讲义第2.6章,项目名 010
你想通过代码,从容器中获取对象。
通过SpringApplication.run(Application.class, args); 的返回值获取Spring容器对象。
再获取业务 bean对象进行调用.【和spring中学的使用 ApplicationContext对象获取Bean差不多】
//SpringApplication.run(Application.class, args); 的返回值是 ConfigurableApplicationContext类型
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args){
return run(new Class[]{primarySource}, args);
}
// ConfigurableApplicationContext接口,是ApplicationContext的子接口。我们之前获取spring容器对象,就是ApplicationContext类型的(spring中学的)
public interface ConfigurableApplicationContext extends ApplicationContext
案例:
@Service("userService") // spring容器创建该对象实例
public class UserServiceImpl implements UserService {
@Override
public void sayHello(String name) {
System.out.println("执行了业务方法的sayHello:"+name);
}
@SpringBootApplication
public class Application {
public static void main(String[] args) {
//获取容器对象
//ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
ApplicationContext ctx = SpringApplication.run(Application.class, args);
//从容器者获取对象
UserService userService = (UserService) ctx.getBean("userService");
userService.sayHello("李四");
}
}
项目见讲义第1.2.7章,项目名为 011
开发中可能会有这样的情景。需要在容器启动后执行一些内容。比如读取配置文件,数据库连接之类的。SpringBoot 给我们提供了两个接口来帮助我们实现这种需求。
这两个接口都 有一个run方法。 执行的时间是在容器对象创建好后, 自动执行run()方法
@FunctionalInterface
public interface CommandLineRunner { // CommandLineRunner:命令行运行程序
void run(String... args) throws Exception;
}
@FunctionalInterface
public interface ApplicationRunner { // 应用运行器
void run(ApplicationArguments args) throws Exception;
}
// 以上两个接口的唯一区别就是:形参类型不同
示例:
@SpringBootApplication public class Application implements CommandLineRunner { // run 方法返回值是容器对象 @Resource private SomeServie someService; public static void main(String[] args) { //1.创建容器对象,同时会创建容器中的对象(<bean>),给其注入值 ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args); // 执行 run方法 System.out.println("容器创建好之后"); } @Override public void run(String... args) throws Exception { String str = service.sayHello("李四"); System.out.println(str); //2. 容器对象创建好,执行 run System.out.println("在容器对象创建好后执行的代码"); } }
项目见讲义第1.3.1章,项目名为 012
拦截器是SpringMVC中一种对象,能拦截器对Controller的请求。【拦截器有三个作用时机】
拦截器框架中有系统的拦截器, 还可以自定义拦截器。 实现对请求预先处理。
1)SpringMVC中实现自定义拦截器:
创建类实现HandlerInterceptor接口
// handler 为 被拦截的控制器对象。 true:请求能被控制器处理;false:请求被截断
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
需在SpringMVC的配置文件中,声明拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:path="url" />
<bean class="拦截器类全限定名称"/>
</mvc:interceptor>
</mvc:interceptors>
2)SpringBoot中注册自定义拦截器:
创建类实现HandlerInterceptor接口(com.zjs.web)
// com.zjs.web
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行了 LoginInterceptor,preHandle()");
return true; // 返回true表明请求能被Controller处理;false表明请求被截断
}
}
在 JacaConfig中 注册拦截器对象(com.zjs.config)
//加了@Configuration注解的类,相当于 xml配置文件 @Configuration public class MyAppConfig implements WebMvcConfigurer { //添加拦截器对象, 注入到容器中 @Override public void addInterceptors(InterceptorRegistry registry) { //创建拦截器对象 HandlerInterceptor interceptor = new LoginInterceptor(); //指定拦截的请求uri地址 String path[]= {"/user/**"}; //指定不拦截的地址 String excludePath[] = {"/user/login"}; //registry.addInterceptor(interceptor)返回的是 InterceptorRegistration类型的对象 registry.addInterceptor(interceptor) .addPathPatterns(path) .excludePathPatterns(excludePath); } }
控制器
@RestController
public class MyController{
// 访问该资源会执行拦截器中的方法
@RequestMapping("user/account")
public String userAccount(){
return "访问user/account地址";
}
// 访问该资源不会执行拦截器中的方法:拦截器中放行了
@RequestMapping("user/login")
public String userLogin(){
return "访问user/login地址";
}
}
项目见讲义第3.2章,项目名为 013
在SpringBoot框架中使用Servlet对象。
使用步骤:
例子:
创建自定义Servlet
//创建Servlet类 com.zjs.web public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //使用HttpServletResponse输出数据,应答结果 resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.println("===执行的是Servlet=="); out.flush(); out.close(); } }
在javaConfig中,注册Servlet
@Configuration // com.zjs.config public class WebApplictionConfig { //定义方法, 注册Servlet对象。ServletRegistrationBean即servlet对象 @Bean public ServletRegistrationBean servletRegistrationBean(){ //public ServletRegistrationBean(T servlet, String... urlMappings) //第一个参数是 Servlet对象, 第二个是url地址 //ServletRegistrationBean bean =new ServletRegistrationBean( new MyServlet(),"/myservlet") // 第二种方式: ServletRegistrationBean bean = new ServletRegistrationBean(); bean.setServlet( new MyServlet()); // serlvet对象 bean.addUrlMappings("/login","/test"); // <url-pattern> url地址(有多个) return bean; } }
项目见讲义第3.3章,项目名为 014
Filter是Servlet规范中的过滤器,可以处理请求, 对请求的参数, 属性进行调整。 常常在过滤器中处理字符编码(一个执行时机)
在框架中使用过滤器:
例子:
// 自定义过滤器类(com.zjs.web)
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("执行了MyFilter,doFilter ");
// 过滤器链(责任链设计模式)
filterChain.doFilter(servletRequest,servletResponse);
}
}
// com.zjs.config
@Configuration
public class WebApplicationConfig {
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter( new MyFilter());
// 拦截所有以user开头的请求
bean.addUrlPatterns("/user/*");
return bean;
}
}
@RestController
public class FilterController{
// 过滤器会拦截 所有以 user开头的uri
@RequestMappin("user/account")
public String userAccount(){
return "user/account";
}
// 该uri不会被过滤器拦截
@RequestMappin("query")
public String userAccount(){
return "query";
}
}
项目见讲义第1.3.4 - 1.3.5章,项目名为 015-016
CharacterEncodingFilter : 解决post请求中乱码的问题
控制器
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("===在Servlet输出中文,默认编码ISO-8859-1===");
out.flush();
out.close();
}
}
第一种方式:
使用步骤:
配置字符集过滤器
@Configuration public class WebSystemConfig { //注册Servlet @Bean public ServletRegistrationBean servletRegistrationBean(){ MyServlet myServlet = new MyServlet(); ServletRegistrationBean reg = new ServletRegistrationBean(myServlet,"/myservlet"); return reg; } //注册中文编码Filter @Bean public FilterRegistrationBean filterRegistrationBean(){ FilterRegistrationBean reg = new FilterRegistrationBean(); //使用框架中的过滤器类 CharacterEncodingFilter filter = new CharacterEncodingFilter(); //指定使用的编码方式 filter.setEncoding("utf-8"); //指定request , response都使用encoding的值 filter.setForceEncoding(true); reg.setFilter(filter); //指定 过滤的url地址 reg.addUrlPatterns("/*"); return reg; } }
修改application.properties文件, 让自定义的过滤器起作用
# SpringBoot中默认已经配置了CharacterEncodingFilter。 编码默认是 ISO-8859-1
# 设置enabled=false 作用是关闭系统中配置好的过滤器, 使用自定义的CharacterEncodingFilter
server.servlet.encoding.enabled=false
第二种方式:(推荐使用)
使用系统默认的字符集过滤器,需要修改application.properties文件。无需在JavaCofig中注册过滤器
// 使用springBoot中默认的 CharacterEncodingFilter
server.port=9001
server.servlet.context-path=/myboot
# 让系统的CharacterEncdoingFilter生效(默认值就是为 true)
server.servlet.encoding.enabled=true
# 指定使用的编码方式
server.servlet.encoding.charset=utf-8
# 强制request,response都使用charset属性的值
server.servlet.encoding.force=true
见第4章讲义
使用MyBatis框架操作数据, 在SpringBoot框架集成MyBatis(ORM:对象关系映射)
创建表并插入数据
使用步骤:
mybatis起步依赖:完成mybatis对象自动配置, 这样就将mybatis中用到的对象放在spring容器中
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
创建实体类Student
创建Dao接口 StudentDao , 创建一个通过id查询学生的方法
创建Dao接口对应的Mapper文件,是一个xml文件, 写对应的sql语句(这里也可以不写mapper文件,直接在Dao接口种使用注解,以及对应的sql语句即可)
创建Service层对象, 创建StudentService接口和他的实现类。 去调用dao对象的方法,完成数据库的操作
创建Controller对象,访问Service。
pom.xml 指定把src/main/java目录中的xml文件包含到classpath中(中指定的)
<!--加入 resource 插件:为了在类路径中找到对应的 Mapper.xml文件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
写application.properties文件:配置数据库的连接信息
server.port=8080
server.servlet.context-path=/myboot
#连接数据库
# 数据库用本机上的,使用虚拟机上的数据库要使用虚拟机的ip
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
#serverTimezone=Asia/Shanghai 设置时区
spring.datasource.username=root
spring.datasource.password=hsp
前端请求:http://lcoalhost:8080/myboot/student/query?id=1
项目见讲义第1.4.1章,项目名为 017
需要添加 web的依赖 和 MyBatis Framework, MySql driver的依赖
@Mapper:放在dao接口的上面, 每个dao接口都需要使用这个注解。
/**
* @Mapper:告诉MyBatis这是dao接口,创建此接口的代理对象。
* 位置:在类的上面
* 类似于 spring中 <mapper>标签的作用
*/
@Mapper
public interface StudentMapper {
// @Select(select name, id, age from student where id = #{stuId})
Student selectById(@Param("stuId") Integer id);
}
个人认为类似于mybaits中以下标签的作用:
<mappers>
<mapper resource="StudentMapper.xml"></mapper>
</mappers>
项目见讲义第1.4.2章,项目名为 018
需要添加 web的依赖 和 MyBatis Framework, MySql driver的依赖
为了避免 @Mapper
注解重复添加的麻烦,可以直接在 Spring Boot 启动器类上 添加@MapperScan("xxx")
注解。不需要再为每一个 Mapper 接口添加 @Mapper
注解。
/**
* @MapperScan: 找到Dao接口和Mapper文件
* basePackages:Dao接口所在的包名
*/
@SpringBootApplication
@MapperScan(basePackages = {"com.bjpowernode.dao","com.bjpowernode.mapper"})
public class Application {
}
项目见讲义第1.4.3章,项目名为 018
现在把Mapper文件放在resources目录下
在resources目录中创建子目录 (自定义的) , 例如mapper
把XXXmapper.xml 文件放到 mapper目录中
在application.properties文件中,指定mapper文件的目录
#指定mapper文件的位置。classpath:表示target/classes目录,编译过后的应用的根路径
mybatis.mapper-locations=classpath:mapper/*.xml
#指定mybatis的日志(此处为控制台输出)
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
在pom.xml中指定 把resources目录中的文件 , 编译到目标目录中
<!--resources插件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
到这里,资源文件指定 的内容才算完善
其实到这里已经用不着编写 mapper.xml文件了。使用纯注解式开发:
在 接口上 使用 @Mapper 告诉MyBatis这是dao接口,创建此接口的代理对象。
在 接口方法上面写sql语句:使用对应的注解,比如 @Select @Insert等等
项目见讲义第1.4.4章,项目名为 019
需要添加 web的依赖 和 MyBatis Framework, MySql driver的依赖
Spring框架中的事务:
例如:使用Jdbc或mybatis访问数据库,使用的事务管理器:DataSourceTransactionManager
声明式事务: 在xml配置文件或者使用注解说明事务控制的内容
控制事务: 隔离级别,传播行为, 超时时间
事务处理方式:
1. Spring框架中的@Transactional
2. aspectj框架可以在xml配置文件中,声明事务控制的内容
SpringBoot中使用事务: 上面的两种方式都可以。
1)在业务方法的上面加入@Transactional , 加入该注解后,该业务方法就有事务功能了。
2)明确的在 主启动类的上面,加入@EnableTransactionManager【启动事务管理器】
例子:
/** * @Transactional: 表示方法的有事务支持 * 默认:使用库的隔离级别;REQUIRED 传播行为;超时时间 -1 * 抛出运行时异常,回滚事务 */ @Resource private StudentMapper studentMapper; @Transactional @Override public int addStudent(Student student) { System.out.println("业务方法addStudent"); int rows = studentDao.insert(student); System.out.println("执行sql语句"); //抛出一个运行时异常, 目的是回滚事务 //int m = 10 / 0 ; return rows; }
插件的配置:
1)pom.xml中中配置插件
<!-- mybatis代码自动生成插件 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<!-- GeneratorMapper.xml配置文件的位置:在项目的根目录下,和src是平级的 -->
<configurationFile>GeneratorMapper.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
2)pom.xml中中添加资源文件绑定
<!--resources插件:处理资源目录-->
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
3)创建 GeneratorMapper.xml 文件 【在项目的根目录下,和src是平级的】
配置好后使用该插件生成代码:
4)配置 application.properties
# 端口,context-path
#配置数据库
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=hsp
# 配置mybatis
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
4)创建service层接口,方法如上
5)创建controller层对象
@RequestMappin("/addStudent")
public String addStudent(String name, Integer age){
Student s = new Student();
s.setName(name);
s.setAge(age);
int rows = service.addStudent(s);
return "添加学生:" + rows;
}
6)启动主启动类(最好在主启动类上加注解 @EnableTransactionManage。@MapperScan别忘了)
7)通过 http://localhost:8080/myboot/addStudent?name=张三&age=26(向控制器传入参数,springmvc中有 讲)
接口: API(Application Programming Interface,应用程序接口)是一些预先定义的接口(如函数、HTTP接口),或指软件系统不同组成部分衔接的约定。 用来提供应用程序与开发人员基于某软件或硬件得以访问的一组例程,而又无需访问源码,或理解内部工作机制的细节。
接口(API): 可以指 访问servlet, controller的url, 调用其他程序的函数
架构风格: api组织方式(样子)
就是一个传统的: http://localhost:9002/mytrans/addStudent?name=lisi&age=26
在地址上提供了 访问的资源名称addStudent, 在其后使用了get方式传递参数。
项目见讲义第1.5章,项目名为 020(对应讲义为1.5.4章)
理论内容可以看这个,实战的话建议看黑马springboot基础篇的项目实战,是一个前后端分离的项目, 采用了RESTful风格(没有涉及到很多东西,只有单表的增删改查)
RESTful架构风格
REST : (英文: Representational State Transfer , 中文: 表现层状态转移)。
REST中的要素:
用REST表示资源和对资源的操作。 在互联网中,表示一个资源或者一个操作。
对资源的操作:
查询资源: 看,通过url找到资源。 (get)
创建资源: 添加资源(post)
更新资源:更新资源 ,编辑(pust)
删除资源: 去除(delete)
资源使用url表示,通过名词表示资源。
在url中,使用名词表示资源, 以及访问资源的信息,。
在url中,使用“ / " 分隔对资源的信息( RESTFul 风格)
比如我们要访问一个 http 接口:http://localhost:8080/boot/order?id=1021&status=1
采用 RESTFul 风格则 http 地址为:http://localhost:8080/boot/order/1021/1
使用http中的动作(请求方式), 表示对资源的操作(CURD)
GET: 查询资源 – sql select 【查:获取资源】
处理单个资源:用他的单数方式
http://localhost:8080/myboot/student/1001
http://localhost:8080/myboot/student/1001/1
处理多个资源:使用复数形式
http://localhost:8080/myboot/students/1001/1002
POST: 创建资源 – sql insert 【增:添加资源】
http://localhost:8080/myboot/student
在post请求中传递数据:
<form action="http://localhost:8080/myboot/student" method="post">
姓名:<input type="text" name="name" />
年龄:<input type="text" name="age" />
</form>
PUT: 更新资源 – sql update 【改:修改资源】
浏览器不能识别、支持 PUT 和 DELETE
// 表示更新 1 这个学生,表单中提交的是新数据
<form action="http://localhost:8080/myboot/student/1" method="post">
姓名:<input type="text" name="name" />
年龄:<input type="text" name="age" />
<input type="hidden" name="_method" value="PUT" /> // 老杜html中y
</form>
DELETE: 删除资源 – sql delete 【删:删除资源】
<a href="http://localhost:8080/myboot/student/1">删除1的数据</a>
需要的分页, 排序等参数,依然放在 url的后面, 不需要使用斜杠传参数。例如
http://localhost:8080/myboot/students?page=1&pageSize=20
一句话说明REST:
注解
@PathVariable : 从url地址中获取数据(零散数据)
@RequstBody:接收前端提交的JSON字符串(封装好的对象)
@GetMapping: 支持get请求方式, 等同于 @RequestMapping( method=RequestMethod.GET)
@PostMapping: 支持post请求方式 ,等同于 @RequestMapping( method=RequestMethod.POST)
@PutMapping: 支持put请求方式, 等同于 @RequestMapping( method=RequestMethod.PUT)
@DeleteMapping: 支持delete请求方式, 等同于 @RequestMapping( method=RequestMethod.DELETE)
@RestController: 符合注解, 是@Controller 和@ResponseBody组合。
在类的上面使用@RestController , 表示当前类者的所有方法都加入了 @ResponseBody
Postman : 测试工具
使用Postman : 可以测试 get ,post , put ,delete 等请求
案例:
创建控制器controller
/*** * 创建资源 Post请求方式:添加学生信息 * http://localhost:8080/myboot/student/zhangsan/20 * 将url中携带的数据 传给控制器方法的形参 * 通过@PathVariable:获取url中的数据。value属性为路径变量名 * {age}:定义路径变量,age为自定义路径变量名称 */ @PostMapping("/student/{name}/{age}") public String createStudent(@PathVariable(value = "name") String name, @PathVariable("age") Integer age){ return "创建资源 student: name="+name+"#age="+age; } /** * 更新资源:更改指定id学生的age * * 当路径变量名称和 形参名一样, @PathVariable中的value可以省略 */ @PutMapping("/student/{id}/{age}") public String modifyStudent(@PathVariable Integer id, @PathVariable Integer age){ return "更新资源, 执行put请求方式: id="+id+"#age="+age; }
使用postman测试:
项目名 020:testrest.html(对应讲义为1.5.4章)
在SpringMVC中 有一个过滤器, 支持将post请求转为put ,delete请求
过滤器: org.springframework.web.filter.HiddenHttpMethodFilter
作用: 把请求中的post请求转为 put , delete
实现步骤:
application.properties(yml) : 开启使用 HiddenHttpMethodFilter 过滤器
# 启用支持 put,delete的过滤器
spring.mvc.hiddenmethod.filter.enabled=true
在请求页面中,包含 _method参数, 他的值是 put 或 delete , 发起这些请求使用的post方式
// resources/static/testrest.html
<form action="student/test" method="post">
<input type="hidden" name="_method" value="PUT" />
<input type="submit" value="测试请求方式" />
</form>
创建控制器对象
@PutMapping("/student/test")
// @RequestMapping("/student/test", method=RequestMethod.PUT)
public String test(){
return "执行student/test,使用的请求方式 put";
}
测试put请求
http://localhost:8080/myboot/student/testrest.html
这样的路径访问会失败, 路径有冲突。(都是get请求方式,访问的路径还相同,控制器不知道该执行哪个方法)
解决:设计路径,必须唯一。 路径 uri 和 请求方式两者的组合 必须满足唯一性
项目见讲义第1.6章
Redis : 一个NoSQL数据库, 常用作 缓存使用 (cache)【在荣姐mybatis中提及过缓存】
Redis的数据类型: string , hash, set, zset, list
Redis是一个中间件: 是一个独立的服务器。
java中著名的客户端: Jedis(在redis笔记中有讲,直接使用Jedis操作redis数据库), lettuce , Redisson
Spring,SpringBoot中有 一个RedisTemplate(StringRedisTemplate) ,处理和redis的交互
Redis-x64-3.2.100.rar 解压缩到一个 非中文 的目录本机Redis安装路径
redis-server.exe:服务端, 启动后,不要关闭
redis-cli.exe:客户端, 访问redis中的数据
redisclient-win32.x86_64.2.0.jar : Redis图形界面客户端 jar包所在路径
执行方式:1. 在这个文件所在的目录, 打开cmd,执行 java -jar redisclient-win32.x86_64.2.0.jar
2. 双击执行该jar包即可
项目实现步骤见讲义1.6.2章,项目名为 021
需要添加 web的依赖 和 Spring Dat Redis 的依赖
springboot中操作redis所导入的依赖:
<!--redis起步依赖: 直接在项目中使用RedisTemplate(StringRedisTemplate)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
点击进入spring-boot-starter-data-redis,你会发现它其实用的核心是 lettuce【lettuce相当于Jedis,我们在redis中已经操作过了Jedis】
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.1.10.RELEASE</version>
<scope>compile</scope>
</dependency>
所以,我们在程序中使用RedisTemplate类的方法 操作redis数据, 实际就是调用的lettuce 客户端的中的方法
导入依赖之后,执行下述操作
在 application.propertie中指定redis
#指定 redis
spring.redis.host=localhost # 使用的是本机的 redis
spring.redis.port=6379
#spring.redis.password=123456
创建控制器对象(添加数据到redis,从redis获取数据)
@SuppressWarnings({"all"}) @RestController // @RestControllerAdvice // springboot中的异常处理器(专门用于处理异常信息) public class RedisController { /** * 注入 RedisTemplate * * RedisTemplate泛型 * 1. RedisTemplate<String, String> * 2. RedisTemplate<Object, Object> * 3. RedisTemplate * * 注意:RedisTemplate对象的名称为 redisTemplate。(默认的名称:按名称注入) */ @Resource private RedisTemplate redisTemplate; @Resource private StringRedisTemplate stringRedisTemplate; // 添加数据到redis @PostMapping("/redis/addString") public String addRedis(String name, String value) { // 操作redis中string类型数据,先获取ValueOperations对象 ValueOperations valueOperations = redisTemplate.opsForValue(); // 添加数据 valueOperations.set("name", "zhangsan"); return "向redis添加string类型数据"; } // 获取redis中的数据 @RequestMapping("/redis/getk") public String getData(String k){ ValueOperations valueOperations = redisTemplate.opsForValue(); Object v = valueOperations.get(k); return "k是:" + k + ",v是:" + v; } // 测试 StringRedisTemplate @PostMapping("/redis/{k}/{v}") public String addStringKV(@PathVariable String k, @PathVariable String v) { // 使用 StringRedisTemplate对象 stringRedisTemplate.opsForValue().set(k, v); return "使用StringRedisTemplate对象"; } @GetMapping("/redis/getStr/{k}") public String getStringValue(@PathVariable String k) { String v = stringRedisTemplate.opsForValue().get(k); return "k的value:" + v; } }
使用postman进行测试
添加数据:
获取数据:
从redis客户端中也可以得到数据
项目实现步骤见讲义1.6.2章,项目名为 021
需要添加 web的依赖 和 Spring Dat Redis 的依赖
序列化:把对象转化为可传输的字节序列过程称为序列化。(对象 ==》 二进制)
反序列化:把字节序列还原为对象的过程称为反序列化。
为什么需要序列化
**序列化最终的目的是为了对象可以跨平台存储,和进行网络传输。**而我们进行跨平台存储和网络传输的方式就是IO,而我们的IO支持的数据格式就是字节数组。
我们必须在把对象转成字节数组的时候就制定一种规则(序列化),那么我们从IO流里面读出数据的时候再以这种规则把对象还原回来(反序列化)。
什么情况下需要序列化
通过上面我想你已经知道了凡是需要进行“跨平台存储”和”网络传输”的数据,都需要进行序列化。
本质上存储和网络传输 都需要经过 把一个对象状态保存成一种跨平台识别的字节格式,然后其他的平台才可以通过字节信息解析还原对象信息。
序列化的方式
序列化只是一种拆装组装对象的规则,那么这种规则肯定也可能有多种多样,比如现在常见的序列化方式有:
JDK(不支持跨语言)、JSON、XML、Hessian、Kryo(不支持跨语言)、Thrift、Protofbuff、
json的序列化:Student( name=zs, age=20) ---- { “name”:“zs”, “age”:20 }
java的序列化: 把java对象转为byte[], 二进制数据
json序列化:json序列化功能将对象转换为 JSON 格式或从 JSON 格式转换对象。例如把一个Student对象转换为JSON字符串{“name”:“李四”, “age”:29} ),反序列化(将JSON字符串 {“name”:“李四”, “age”:29} 转换为Student对象)
设置置RedisTemplate的序列化方式
// 设置RedisTemplate的序列化机制:在存取值之前,设置序列化
// RedisSerializer接口的实现类:不同的序列化机制
// 设置 key 使用String的序列化:使用字符串的序列化
redisTemplate.setKeySerializer( new StringRedisSerializer());
// 设置 value 的序列化
redisTemplate.setValueSerializer( new StringRedisSerializer());
// 存值
redisTemplate.opsForValue().set(k,v);
项目名为 021
当要为某个类生成序列化版本号时,将光标位于类名,按alt + enter 就有快捷键出现。【序列化要实现接口Serializable】
使用json序列化,将java对象转换为json存储
public class Student implements Serializable {
private static final long serialVersionUID = 6957173297825217669L;
private Integer id;
private String name;
private Integer age;
// ...
}
// 将java对象转为json格式的字符串存储到redis中 @PostMapping("/redis/addjson") public String addJson(){ Student student = new Student(); student.setId(1001); student.setName("zhangsan"); student.setAge(20); // 把 key 作为 string序列化 redisTemplate.setKeySerializer(new StringRedisSerializer()); // 把值作为json序列化 redisTemplate.setValueSerializer( new Jackson2JsonRedisSerializer(Student.class) ); redisTemplate.opsForValue().set("mystudent", student); return "json序列化"; } @PostMapping("/redis/getjson") public String getJson(){ redisTemplate.setKeySerializer(new StringRedisSerializer()); // 把值作为json序列化(反序列化) redisTemplate.setValueSerializer( new Jackson2JsonRedisSerializer(Student.class) ); Object obj = redisTemplate.opsForValue().get("mystudent"); return "json反序列化="+ obj; }
https://github.com/apache/dubbo-spring-boot-project/blob/master/README_CN.md
公共接口项目:022
独立的maven项目(创建普通的java项目,不过使用了maven构建): 定义了接口和数据类
public class Student implements Serializable {
private static final long serialVersionUID = 1901229007746699151L;
private Integer id;
private String name;
private Integer age;
// ...
}
public interface StudentService {
Student queryStudent(Integer id);
}
服务提供者:023
创建SpringBoot项目
1) pom.xml
<dependencies> <!--加入公共项目的gav(坐标 )--> <dependency> <groupId>com.bjpowernode</groupId> <artifactId>022-interface-api</artifactId> <version>1.0.0</version> </dependency> <!--dubbo依赖--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.8</version> </dependency> <!--zookeeper依赖--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>2.7.8</version> <type>pom</type> <exclusions> <!-- 排除log4j依赖 --> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> </exclusions> </dependency> </dependencies>
2)实现接口
/** * 使用dubbo中的注解暴露服务 * @Component 可以不用加 */ @DubboService(interfaceClass = StudentService.class,version = "1.0",timeout = 5000) public class StudentServiceImpl implements StudentService { @Override public Student queryStudent(Integer id) { Student student = new Student(); if( 1001 == id){ student.setId(1001); student.setName("------1001-张三"); student.setAge(20); } else if(1002 == id){ student.setId(1002); student.setName("#######1002-李四"); student.setAge(22); } return student; } }
3)application.properties
#配置服务名称 dubbo:application name="名称"
spring.application.name=studentservice-provider
#配置扫描的包, 扫描的@DubboService
dubbo.scan.base-packages=com.bjpowernode.service
#配置dubbo协议(这里使用注册中心,不需要配置)
#dubbo.protocol.name=dubbo
#dubbo.protocol.port=20881
#注册中心
dubbo.registry.address=zookeeper://localhost:2181
4)在启动类的上面
@SpringBootApplication
@EnableDubbo // 启用Dubbo
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
服务提供者:024
创建SpringBoot项目(web依赖)
1) pom.xml
<dependencies> <!--加入公共项目的gav--> <dependency> <groupId>com.bjpowernode</groupId> <artifactId>022-interface-api</artifactId> <version>1.0.0</version> </dependency> <!--dubbo依赖--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.8</version> </dependency> <!--zookeeper依赖--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>2.7.8</version> <type>pom</type> <exclusions> <!-- 排除log4j依赖 --> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> </exclusions> </dependency> </dependencies>
@RestController
public class DubboController {
// 引用远程服务, 把创建好的代理对象,注入给studentService
//@DubboReference(interfaceClass = StudentService.class,version = "1.0")
// 没有使用interfaceClass,默认的就是 引用类型的 数据类型
@DubboReference(version = "1.0")
private StudentService studentService;
@GetMapping("/query")
public String queryStudent(Integer id){
Student student = studentService.queryStudent(id);
return "调用远程接口,获取对象:"+student;
}
}
3)application.properties
#指定服务名称
spring.application.name=consumer-application
#指定注册中心
dubbo.registry.address=zookeeper://localhost:2181
使用的技术: SpringBoot ,Dubbo, Redis, MyBatis
Student表:
CREATE TABLE student
(
id
int(11) NOT NULL AUTO_INCREMENT,
name
varchar(255) COLLATE utf8_bin DEFAULT NULL,
phone
varchar(11) COLLATE utf8_bin DEFAULT NULL,
age
int(11) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
phone必须唯一, 如果已经存在了手机号, 注册失败的。
int addStudent(Student student);
返回值:int
1: 注册成功
2 : 手机号已经存在
name至少两个字符,
age 必须 大于 0
先到redis查询学生, 如果redis没有此学生,从数据库查询, 把查询到的学生放入到redis。
后面再次查询这个学生应该从redis就能获取到。
Student queryStudent(Integer id);
消费者可以是一个Controller , 调用提供者的两个方法。 实现注册和查询。
在html页面中提供 form 注册学生, 提供文本框输入id,进行查询。
注册和查询都使用ajax技术。
html,jquery.js都放到resources/static目录中
1.创建了一个jsp应用(第2.7节:上依赖,上配置)
2.修改pom.xml
指定打包后的文件名称
<build>
<!--打包后的文件名称-->
<finalName>myboot</finalName>
</build>
指定jsp编译目录
<!--resources插件, 把jsp编译到指定的目录--> <resources> <resource> <directory>src/main/webapp</directory> <targetPath>META-INF/resources</targetPath> <includes> <include>**/*.*</include> </includes> </resource> <!--使用了mybatis ,而且mapper文件放在src/main/java目录--> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <!--把src/main/resources下面的所有文件,都包含到classes目录--> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> </includes> </resource> </resources>
执行打包是war
<!--打包类型-->
<packaging>war</packaging>
主启动类继承SpringBootServletInitializer
/** * SpringBootServletInitializer: 继承这个类, 才能使用独立tomcat服务器 * SpringBootServletInitializer就是原有的web.xml文件的替代 */ @SpringBootApplication public class JspApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(JspApplication.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(JspApplication.class); } }
使用了Maven的插件进行打包(lifecycle中的clean package指令)
部署war
把war放到tomcat等服务器的发布目录中。 tomcat为例, myboot.war放到tomcat/webapps目录。
war包需发布到服务器才能够运行
创建了一个包含了jsp的项目(第2.7节:上依赖,上配置)
修改pom.xml
指定打包后的文件名称
<build>
<!--打包后的文件名称-->
<finalName>myboot</finalName>
</build>
指定springboot-maven-plugin版本
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--打包jar, 有jsp文件时,必须指定maven-plugin插件的版本是 1.4.2.RELEASE-->
<version>1.4.2.RELEASE</version>
</plugin>
</plugins>
最后执行 maven clean package
在target目录中,生成jar 文件, 例子是myboot.jar
执行独立的springboot项目 在cmd中 java -jar myboot.jar
jar包双击即可运行(要有jdk环境)
现在都是前后端分离项目了,这个以后再说。你们随意
Thymeleaf: 是使用java开发的模板技术, 在服务器端运行。 把处理后的数据发送给浏览器。
模板是作视图层工作的。 显示数据的。 Thymeleaf是基于Html语言。 Thymleaf语法是应用在
html标签中 。 SpringBoot框架集成Thymealeaf, 使用Thymeleaf代替jsp。
Thymeleaf 的官方网站:http://www.thymeleaf.org
Thymeleaf 官方手册:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
标准变量表达式
语法: ${key}
作用: 获取key对于的文本数据, key 是request作用域中的key , 使用request.setAttribute(), model.addAttribute()
在页面中的 html标签中, 使用 th:text=“${key}”
<div style="margin-left: 400px">
<h3>标准变量表达式: ${key}</h3>
<p th:text="${site}">key不存在</p>
<br/>
<p>获取SysUser对象 属性值</p>
<p th:text="${myuser.id}">id</p>
<p th:text="${myuser.name}">姓名</p>
<p th:text="${myuser.sex}">姓名:m男</p>
<p th:text="${myuser.age}">年龄</p>
<p th:text="${myuser.getName()}">获取姓名使用getXXX</p>
</div>
选择变量表达式( 星号变量表达式)
语法: *{key}
作用: 获取这个key对应的数据, *{key}需要和th:object 这个属性一起使用。
目的是简单获取对象的属性值。
<p>使用 *{} 获取SysUser的属性值</p>
<div th:object="${myuser}">
<p th:text="*{id}"></p>
<p th:text="*{name}"></p>
<p th:text="*{sex}"></p>
<p th:text="*{age}"></p>
</div>
<p>使用*{}完成的表示 对象的属性值</p>
<p th:text="*{myuser.name}" ></p>
链接表达式
语法: @{url}
作用: 表示链接, 可以
<script src="..."> , <link href="..."> <a href=".."> ,<form action="..."> <img src="...">
属性是放在html元素中的,就是html元素的属性,加入了th前缀。 属性的作用不变。 加入上th, 属性的值由模板引擎处理了。 在属性可以使用变量表达式
例如:
<form action="/loginServlet" method="post"></form>
<form th:action="/loginServlet" th:method="${methodAttr}"></form>
each循环, 可以循环List,Array
语法:
在一个html标签中,使用th:each
<div th:each="集合循环成员,循环的状态变量:${key}">
<p th:text="${集合循环成员}" ></p>
</div>
集合循环成员,循环的状态变量:两个名称都是自定义的。 “循环的状态变量”这个名称可以不定义,默认是"集合循环成员Stat"
each循环Map
在一个html标签中,使用th:each
<div th:each="集合循环成员,循环的状态变量:${key}">
<p th:text="${集合循环成员.key}" ></p>
<p th:text="${集合循环成员.value}" ></p>
</div>
集合循环成员,循环的状态变量:两个名称都是自定义的。 “循环的状态变量”这个名称可以不定义,默认是"集合循环成员Stat"
key:map集合中的key
value:map集合key对应的value值
“th:if” : 判断语句, 当条件为true, 显示html标签体内, 反之不显示 没有else语句
语法:
<div th:if=" 10 > 0 "> 显示文本内容 </div>
还有一个 th:unless 和 th:if相反的行为
语法:
<div th:unless=" 10 < 0 "> 当条件为false显示标签体内容 </div>
例子:if
<div style="margin-left: 400px">
<h3> if 使用</h3>
<p th:if="${sex=='m'}">性别是男</p>
<p th:if="${isLogin}">已经登录系统</p>
<p th:if="${age > 20}">年龄大于20</p>
<!--""空字符是true-->
<p th:if="${name}">name是“”</p>
<!--null是false-->
<p th:if="${isOld}"> isOld是null</p>
</div>
例子: unless
<div style="margin-left: 400px">
<h3>unless: 判断条件为false,显示标签体内容</h3>
<p th:unless="${sex=='f'}">性别是男的</p>
<p th:unless="${isLogin}">登录系统</p>
<p th:unless="${isOld}"> isOld是null </p>
</div>
th:switch 和 java中的swith一样的
语法:
<div th:switch="要比对的值">
<p th:case="值1">
结果1
</p>
<p th:case="值2">
结果2
</p>
<p th:case="*">
默认结果
</p>
以上的case只有一个语句执行
</div>
内联text: 在html标签外,获取表达式的值
语法:
<p>显示姓名是:[[${key}]]</p>
<div style="margin-left: 400px">
<h3>内联 text, 使用内联表达式显示变量的值</h3>
<div th:inline="text">
<p>我是[[${name}]],年龄是[[${age}]]</p>
我是<span th:text="${name}"></span>,年龄是<span th:text="${age}"></span>
</div>
<div>
<p>使用内联text</p>
<p>我是[[${name}]],性别是[[${sex}]]</p>
</div>
</div>
内联javascript
例子:
<script type="text/javascript" th:inline="javascript">
var myname = [[${name}]];
var myage = [[${age}]];
//alert("获取的模板中数据 "+ myname + ","+myage)
function fun(){
alert("单击事件,获取数据 "+ myname + ","+ [[${sex}]])
}
</script>
例子:
<div style="margin-left: 400px">
<h3>文本字面量: 使用单引号括起来的字符串</h3>
<p th:text="'我是'+${name}+',我所在的城市'+${city}">数据显示</p>
<h3>数字字面量</h3>
<p th:if="${20>5}"> 20大于 5</p>
<h3>boolean字面量</h3>
<p th:if="${isLogin == true}">用户已经登录系统</p>
<h3>null字面量</h3>
<p th:if="${myuser != null}">有myuser数据</p>
</div>
连接字符串有两种语法
1) 语法使用 单引号括起来字符串 , 使用 + 连接其他的 字符串或者表达式
<p th:text="'我是'+${name}+',我所在的城市'+${city}">数据显示</p>
2)语法:使用双竖线, |字符串和表达式|
<p th:text="|我是${name},我所在城市${city|">
显示数据
</p>
例子:
<div style="margin-left: 400px">
<h3>字符串连接方式1:使用单引号括起来的字符串</h3>
<p th:text="'我是'+${name}+',我所在的城市'+${city}">数据显示</p>
<br/>
<br/>
<h3>字符串连接方式2:|字符串和表达式|</h3>
<p th:text="|我是${name},所在城市${city},其他人${myuser.name}|"></p>
</div>
算术运 算: + , - - , * , / , % 关系比较 : > , < , >= , <= ( gt , lt , ge , le ) 相等判断: == , != ( eq , ne ) <div style="margin-left: 400px"> <h3>使用运算符</h3> <p th:text="${age > 10}">年龄大于 10 </p> <p th:text="${ 20 + 30 }">显示运算结果</p> <p th:if="${myuser == null}">myuser是null</p> <p th:if="${myuser eq null}">myuser是null</p> <p th:if="${myuser ne null}">myuser不是null</p> <p th:text="${isLogin == true ? '用户已经登录' : '用户需要登录'}"></p> <p th:text="${isLogin == true ? ( age > 10 ? '用户是大于10的' : '用户年龄比较小') : '用户需要登录'}"></p> </div> 三元运算符: 表达式 ? true的结果 : false的结果 三元运算符可以嵌套
文档地址:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#web-context-namespaces-for-requestsession-attributes-etc.
#request 表示 HttpServletRequest
#session 表示 HttpSession对象
session 表示Map对象的, 是#session的简单表示方式, 用来获取session中指定的key的值
#session.getAttribute(“loginname”) == session.loginname
这些是内置对象,可以在模板文件中直接使用。
例子: <div style="margin-left: 350px"> <h3>内置对象#request,#session,session的使用</h3> <p>获取作用域中的数据</p> <p th:text="${#request.getAttribute('requestData')}"></p> <p th:text="${#session.getAttribute('sessionData')}"></p> <p th:text="${session.loginname}"></p> <br/> <br/> <h3>使用内置对象的方法</h3> getRequestURL=<span th:text="${#request.getRequestURL()}"></span><br/> getRequestURI=<span th:text="${#request.getRequestURI()}"></span><br/> getQueryString=<span th:text="${#request.getQueryString()}"></span><br/> getContextPath=<span th:text="${#request.getContextPath()}"></span><br/> getServerName=<span th:text="${#request.getServerName()}"></span><br/> getServerPort=<span th:text="${#request.getServerPort()}"></span><br/> </div>
内置工具类型: Thymeleaf自己的一些类,提供对string, date ,集合的一些处理方法
#dates: 处理日器的工具类
#numbers:处理数字的
#lists: 处理list集合的
<div style="margin-left: 350px"> <h3>日期类对象 #dates</h3> <p th:text="${#dates.format(mydate )}"></p> <p th:text="${#dates.format(mydate,'yyyy-MM-dd')}"></p> <p th:text="${#dates.format(mydate,'yyyy-MM-dd HH:mm:ss')}"></p> <p th:text="${#dates.year(mydate)}"></p> <p th:text="${#dates.month(mydate)}"></p> <p th:text="${#dates.monthName(mydate)}"></p> <p th:text="${#dates.createNow()}"></p> <br/> <h3>内置工具类#numbers,操作数字的</h3> <p th:text="${#numbers.formatCurrency(mynum)}"></p> <p th:text="${#numbers.formatDecimal(mynum,5,2)}"></p> <br/> <h3>内置工具类#strings,操作字符串</h3> <p th:text="${#strings.toUpperCase(mystr)}"></p> <p th:text="${#strings.indexOf(mystr,'power')}"></p> <p th:text="${#strings.substring(mystr,2,5)}"></p> <p th:text="${#strings.substring(mystr,2)}"></p> <p th:text="${#strings.concat(mystr,'---java开发的黄埔军校---')}"></p> <p th:text="${#strings.length(mystr)}"></p> <p th:text="${#strings.length('hello')}"></p> <p th:unless="${#strings.isEmpty(mystr)}"> mystring 不是 空字符串 </p> <br/> <h3>内置工具类#lists,操作list集合</h3> <p th:text="${#lists.size(mylist)}"></p> <p th:if="${#lists.contains(mylist,'a')}">有成员a</p> <p th:if="!${#lists.isEmpty(mylist)}"> list 集合有多个成员</p> <br/> <h3>处理null</h3> <p th:text="${zoo?.dog?.name}"></p> </div>
模板是内容复用, 定义一次,在其他的模板文件中多次使用。
模板使用:
定义模板
使用模板
模板定义语法:
th:fragment="模板自定义名称"
例如:
<div th:fragment="head">
<p>
动力节点-java开发
</p>
<p>
www.bjpowernode.com
</p>
</div>
引用模板语法:
1) ~{templatename :: selector}
templatename: 文件名称
selector: 自定义模板名称
2)templatename :: selector
templatename: 文件名称
selector: 自定义模板名称
对于使用模板:有包含模板(th:include), 插入模板(th:insert)
Spring + SpringMVC + SpringBoot
创建对象的: @Controller: 放在类的上面,创建控制器对象,注入到容器中 @RestController: 放在类的上面,创建控制器对象,注入到容器中。 作用:复合注解是@Controller , @ResponseBody, 使用这个注解类的,里面的控制器方法的 返回值都是数据 @Service : 放在业务层的实现类上面,创建service对象,注入到容器 @Repository : 放在dao层的实现类上面,创建dao对象,放入到容器。 没有使用这个注解,是因为现在使用MyBatis 框架,dao对象是MyBatis通过代理生成的。不需要使用@Repository,所以没有使用。 @Component: 放在类的上面,创建此类的对象,放入到容器中。 赋值的: @Value : 简单类型的赋值, 例如 在属性的上面使用@Value("李四") private String name 还可以使用@Value,获取配置文件者的数据(properties或yml)。 @Value("${server.port}") private Integer port @Autowired: 引用类型赋值自动注入的,支持byName, byType. 默认是byType 。 放在属性的上面,也可以放在构造 方法的上面。 推荐是放在构造方法的上面 @Qualifer: 给引用类型赋值,使用byName方式。 @Autowird, @Qualifer都是Spring框架提供的。 @Resource : 来自jdk中的定义, javax.annotation。 实现引用类型的自动注入, 支持byName, byType. 默认是byName, 如果byName失败, 再使用byType注入。 在属性上面使用 其他: @Configuration : 放在类的上面,表示这是个配置类,相当于xml配置文件 @Bean:放在方法的上面, 把方法的返回值对象,注入到spring容器中。 @ImportResource : 加载其他的xml配置文件, 把文件中的对象注入到spring容器中 @PropertySource : 读取其他的properties属性配置文件 @ComponentScan: 扫描器 ,指定包名,扫描注解的 @ResponseBody: 放在方法的上面,表示方法的返回值是数据, 不是视图 @RequestBody : 把请求体中的数据,读取出来, 转为java对象使用。 @ControllerAdvice: 控制器增强, 放在类的上面, 表示此类提供了方法,可以对controller增强功能。 @ExceptionHandler : 处理异常的,放在方法的上面 @Transcational : 处理事务的, 放在service实现类的public方法上面, 表示此方法有事务 SpringBoot中使用的注解 @SpringBootApplication : 放在启动类上面, 包含了@SpringBootConfiguration @EnableAutoConfiguration, @ComponentScan MyBatis相关的注解 @Mapper : 放在类的上面 , 让MyBatis找到接口, 创建他的代理对象 @MapperScan :放在主类的上面 , 指定扫描的包, 把这个包中的所有接口都创建代理对象。 对象注入到容器中 @Param : 放在dao接口的方法的形参前面, 作为命名参数使用的。 Dubbo注解 @DubboService: 在提供者端使用的,暴露服务的, 放在接口的实现类上面 @DubboReference: 在消费者端使用的, 引用远程服务, 放在属性上面使用。 @EnableDubbo : 放在主类上面, 表示当前引用启用Dubbo功能。
p>
mystring 不是 空字符串
<br/>
<h3>内置工具类#lists,操作list集合</h3>
<p th:text="${#lists.size(mylist)}"></p>
<p th:if="${#lists.contains(mylist,'a')}">有成员a</p>
<p th:if="!${#lists.isEmpty(mylist)}"> list 集合有多个成员</p>
<br/>
<h3>处理null</h3>
<p th:text="${zoo?.dog?.name}"></p>
模板是内容复用, 定义一次,在其他的模板文件中多次使用。
模板使用:
定义模板
使用模板
模板定义语法:
th:fragment="模板自定义名称"
例如:
<div th:fragment="head">
<p>
动力节点-java开发
</p>
<p>
www.bjpowernode.com
</p>
</div>
引用模板语法:
1) ~{templatename :: selector}
templatename: 文件名称
selector: 自定义模板名称
2)templatename :: selector
templatename: 文件名称
selector: 自定义模板名称
对于使用模板:有包含模板(th:include), 插入模板(th:insert)
Spring + SpringMVC + SpringBoot
创建对象的: @Controller: 放在类的上面,创建控制器对象,注入到容器中 @RestController: 放在类的上面,创建控制器对象,注入到容器中。 作用:复合注解是@Controller , @ResponseBody, 使用这个注解类的,里面的控制器方法的 返回值都是数据 @Service : 放在业务层的实现类上面,创建service对象,注入到容器 @Repository : 放在dao层的实现类上面,创建dao对象,放入到容器。 没有使用这个注解,是因为现在使用MyBatis 框架,dao对象是MyBatis通过代理生成的。不需要使用@Repository,所以没有使用。 @Component: 放在类的上面,创建此类的对象,放入到容器中。 赋值的: @Value : 简单类型的赋值, 例如 在属性的上面使用@Value("李四") private String name 还可以使用@Value,获取配置文件者的数据(properties或yml)。 @Value("${server.port}") private Integer port @Autowired: 引用类型赋值自动注入的,支持byName, byType. 默认是byType 。 放在属性的上面,也可以放在构造 方法的上面。 推荐是放在构造方法的上面 @Qualifer: 给引用类型赋值,使用byName方式。 @Autowird, @Qualifer都是Spring框架提供的。 @Resource : 来自jdk中的定义, javax.annotation。 实现引用类型的自动注入, 支持byName, byType. 默认是byName, 如果byName失败, 再使用byType注入。 在属性上面使用 其他: @Configuration : 放在类的上面,表示这是个配置类,相当于xml配置文件 @Bean:放在方法的上面, 把方法的返回值对象,注入到spring容器中。 @ImportResource : 加载其他的xml配置文件, 把文件中的对象注入到spring容器中 @PropertySource : 读取其他的properties属性配置文件 @ComponentScan: 扫描器 ,指定包名,扫描注解的 @ResponseBody: 放在方法的上面,表示方法的返回值是数据, 不是视图 @RequestBody : 把请求体中的数据,读取出来, 转为java对象使用。 @ControllerAdvice: 控制器增强, 放在类的上面, 表示此类提供了方法,可以对controller增强功能。 @ExceptionHandler : 处理异常的,放在方法的上面 @Transcational : 处理事务的, 放在service实现类的public方法上面, 表示此方法有事务 SpringBoot中使用的注解 @SpringBootApplication : 放在启动类上面, 包含了@SpringBootConfiguration @EnableAutoConfiguration, @ComponentScan MyBatis相关的注解 @Mapper : 放在类的上面 , 让MyBatis找到接口, 创建他的代理对象 @MapperScan :放在主类的上面 , 指定扫描的包, 把这个包中的所有接口都创建代理对象。 对象注入到容器中 @Param : 放在dao接口的方法的形参前面, 作为命名参数使用的。 Dubbo注解 @DubboService: 在提供者端使用的,暴露服务的, 放在接口的实现类上面 @DubboReference: 在消费者端使用的, 引用远程服务, 放在属性上面使用。 @EnableDubbo : 放在主类上面, 表示当前引用启用Dubbo功能。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。