当前位置: 首页 > news >正文

SpringBoot基础入门

SpringBoot2讲义链接 源码链接 springboot中文网

由于讲义中有代码的详细实现步骤,故此笔记只记录理论部分,项目具体构建细节需搭配 讲义 食用

csdn比较好的博客

第一章 JavaConfig

项目见讲义第1章,项目名为 001-springboot-pre Xml 配置容器(用maven但没有用模板)

  1. 为什么要使用 Spring Boot

    因为Spring, SpringMVC 需要使用的大量的配置文件 (xml文件)

    还需要配置各种对象,把使用的对象放入到spring容器中才能使用对象

    需要了解其他框架配置规则。

  2. SpringBoot 就相当于 不需要配置文件的Spring+SpringMVC。 常用的框架和第三方库都已经配置好了。

    拿来就可以使用了。

  3. SpringBoot开发效率高,使用方便多了

1.1 JavaConfig(@Configuration, @Bean)

JavaConfig: 使用java类作为xml配置文件的替代, 是配置spring容器的纯java的方式。 在这个java类这可以创建java对象,把对象放入spring容器中(注入到容器)

一般用来导入第三方Bean,函数的返回值设置为第三方Bean对象即可

要完成以上功能,需要使用以下两个注解:

  1. @Configuration: 放在一个类的上面,表示这个类是作为配置文件使用的。相当于xml

  2. @Bean:声明对象,把对象注入到容器中。

    • 不指定对象的名称,默认对象名称是方法名
    • name属性,指定对象的名称

例子:

// 先创建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属性的值**/    @Beanpublic 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");  // 获取容器中的对象
1.2 @ImportResource

@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也会被装载到容器中。

1.3 @PropertyResource

@PropertyResource: 读取properties属性配置文件。

​ 使用属性配置文件可以实现外部化配置 ,在程序代码之外提供数据。

步骤:

  1. 在resources目录下,创建properties文件, 使用k=v的格式提供数据

  2. 在配置类上使用 @PropertyResource 指定properties文件的位置,使用@ComponentScan创建实体类对象实例

  3. 实体类用@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文件

第二 章 Spring Boot

2.1 介绍

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,做配置

2.2 创建Spring Boot项目

项目见讲义第1.2.1 - 1.2.3章,项目名 002 - 004

使用Spring提供的初始化器, 就是向导创建SpringBoot应用 【见讲义1.2节】

使用的地址: https://start.spring.io

1. 利用向导

SpringBoot项目的结构:

image-20210115152427829

使用国内的地址

https://start.springboot.io

image-20210115155556662

2 使用maven

见讲义(就是直接导入坐标而已)

3. 最终使用的方式

新版本idea只有springBoot3的创建,最低jdk版本支持也变成了jdk17。为了使用springBoot2.4.2,将https://start.spring.io/或者http://start.springboot.io/替换为 https://start.aliyun.com/

目前只添加了 Spring Web的依赖

注意:使用这种方式,它会在单独的一个包下为我们创建主启动类,我们将主启动类放到上一级目录下。因为该级目录下以后会有子包,对应着我们的三层架构,这样做的目的是为了运行主启动类时,扫描该类所在的包和所有子包

2.3 注解的使用

项目005:由于springBoot内嵌了tomcat,所以可以直接通过请求访问资源

1. 起步依赖
<!--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。因为没有在配置文件中指定项目名,所以可以这样写

2.@SpringBootApplication注解

@SpringBootApplication是一个复合注解:由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三者组成

@SpringBootApplication:Springboot应用标注在某个类上,说明是Springboot的自动配置类。springboot运行这个类的main方法启动sprigboot的应用

  1. @SpringBootConfiguration

    @Configuration  // JavaCofig:可声明对象<bean>
    public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
    }
    
    • 说明:使用了@SpringBootConfiguration注解标注的类是可以作为配置文件使用(JavaConfig)的,可以可以在该类里面使用@Bean声明对象,注入到容器
  2. @EnableAutoConfiguration

    • 启用自动配置, 把java对象配置好,注入到spring容器中。例如可以把mybatis的对象创建好,放入到容器中
  3. @ComponentScan

    • @ComponentScan 组件扫描器,找到注解,根据注解的功能创建对象,给属性赋值等等。

    • 默认扫描的包: @ComponentScan所在的类所在的包和子包。

2.4 SpringBoot的配置文件

项目见讲义第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: 8083servlet:context-path: /myboot2

访问路径:http://localhost:8083/myboot2/hello

2.5 多环境配置

项目见讲义第1.2.4.3章,项目名为 007)

有开发环境, 测试环境, 上线的环境。

每个环境有不同的配置信息, 例如端口, 上下文件, 数据库url,用户名,密码等等

使用多环境配置文件,可以方便的切换不同的配置。

使用方式: 创建多个配置文件, 名称规则: application-环境名称.properties(yml)

配置文件是普通的文件,通过 new File创建即可,要加后缀

  1. 创建开发环境的配置文件: application-dev.properties( application-dev.yml )

  2. 创建测试者使用的配置: application-test.properties

  3. 在application.properties中指定使用哪一个配置:

# 指定使用 开发环境的配置文件
spring.profiles.active=dev   // profiles 配置
2.6 @ConfigurationProperties

项目见讲义第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

2.7 使用jsp

项目见讲义第1.2.5章,项目名为 009

SpringBoot不推荐使用jsp ,而是使用模板技术代替jsp(第9章)

使用jsp需要配置:

  1. 加入一个处理jsp的依赖。 负责编译jsp文件
<dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId>
</dependency>
  1. 如果需要使用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>
    
    1. 没有指定版本的,使用springboot默认配置的版本(标签中的中指定的版本)

    2. 指定版本的,使用指定版本。

  1. 创建一个存放jsp的目录,一般叫做webapp(src/main/webapp),在该目录下创建jsp文件

    • 如果在webapp目录上右键,没有创建jsp的选项,可以在Project Structure中指定webapp目录,为 Web Resource Directory

      image-20240204150440742

  2. 创建Controller, 跳转到上述 jsp文件(使用的是视图的逻辑名称【不是全路径名,而是文件名,具体见MVC笔记】,要配置视图解析器)

  3. 在application.propertis文件中配置视图解析器

    #配置 SpringMVC 的视图解析器
    #其中:前缀 / 相当于 src/main/webapp 目录
    spring.mvc.view.prefix=/
    spring.mvc.view.suffix=.jsp
    
  4. 需要在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.8 使用容器对象

项目见讲义第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 {@Overridepublic 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("李四");}
}
2.9 CommandLineRunner 接口 , ApplcationRunner接口

项目见讲义第1.2.7章,项目名为 011

开发中可能会有这样的情景。需要在容器启动后执行一些内容。比如读取配置文件,数据库连接之类的。SpringBoot 给我们提供了两个接口来帮助我们实现这种需求。

  • CommandLineRunner
  • ApplicationRunner

这两个接口都 有一个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 方法返回值是容器对象@Resourceprivate SomeServie someService;public static void main(String[] args) {//1.创建容器对象,同时会创建容器中的对象(<bean>),给其注入值ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);  // 执行 run方法	System.out.println("容器创建好之后"); }@Overridepublic void run(String... args) throws Exception {        String str = service.sayHello("李四");System.out.println(str);//2. 容器对象创建好,执行 runSystem.out.println("在容器对象创建好后执行的代码");}
}

第三章 Web组件

3.1 拦截器Interceptor

项目见讲义第1.3.1章,项目名为 012

拦截器是SpringMVC中一种对象,能拦截器对Controller的请求。【拦截器有三个作用时机】

拦截器框架中有系统的拦截器, 还可以自定义拦截器。 实现对请求预先处理。

1)SpringMVC中实现自定义拦截器:

  1. 创建类实现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 {}
    }
    
  2. 需在SpringMVC的配置文件中,声明拦截器

    <mvc:interceptors><mvc:interceptor><mvc:path="url" /><bean class="拦截器类全限定名称"/></mvc:interceptor>
    </mvc:interceptors>
    

2)SpringBoot中注册自定义拦截器:

  1. 创建类实现HandlerInterceptor接口(com.zjs.web)

    // com.zjs.web
    public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("执行了 LoginInterceptor,preHandle()");return true; // 返回true表明请求能被Controller处理;false表明请求被截断}
    }
    
  2. 在 JacaConfig中 注册拦截器对象(com.zjs.config)

    //加了@Configuration注解的类,相当于 xml配置文件
    @Configuration
    public class MyAppConfig implements WebMvcConfigurer {//添加拦截器对象, 注入到容器中@Overridepublic 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);}
    }
    
  3. 控制器

    @RestController
    public class MyController{// 访问该资源会执行拦截器中的方法@RequestMapping("user/account")public String userAccount(){return "访问user/account地址";}// 访问该资源不会执行拦截器中的方法:拦截器中放行了@RequestMapping("user/login")public String userLogin(){return "访问user/login地址";}
    }
    
3.2 Servlet

项目见讲义第3.2章,项目名为 013

在SpringBoot框架中使用Servlet对象。

使用步骤:

  1. 创建Servlet类。 创建类继承HttpServlet
  2. 注册Servlet 。让框架能找到Servlet
    • ServletRegistrationBean

例子:

  1. 创建自定义Servlet

    //创建Servlet类 com.zjs.web
    public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected 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();}
    }
    
  2. 在javaConfig中,注册Servlet

    @Configuration  // com.zjs.config  
    public class WebApplictionConfig {//定义方法, 注册Servlet对象。ServletRegistrationBean即servlet对象@Beanpublic 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 过滤器Filter

项目见讲义第3.3章,项目名为 014

Filter是Servlet规范中的过滤器,可以处理请求, 对请求的参数, 属性进行调整。 常常在过滤器中处理字符编码(一个执行时机)

在框架中使用过滤器:

  1. 创建自定义过滤器类
  2. 注册Filter过滤器对象
    • FilterRegistrationBean

例子:

  1. 创建自定义的过滤器类
// 自定义过滤器类(com.zjs.web)
public class MyFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("执行了MyFilter,doFilter ");// 过滤器链(责任链设计模式)filterChain.doFilter(servletRequest,servletResponse);}
}
  1. 在javaConfig中,注册Filter过滤器对象
// com.zjs.config
@Configuration
public class WebApplicationConfig {@Beanpublic FilterRegistrationBean filterRegistrationBean(){FilterRegistrationBean bean  = new FilterRegistrationBean();bean.setFilter( new MyFilter());// 拦截所有以user开头的请求bean.addUrlPatterns("/user/*");return bean;}
}
  1. 创建控制器
@RestController
public class FilterController{// 过滤器会拦截 所有以 user开头的uri@RequestMappin("user/account")public String userAccount(){return "user/account";}// 该uri不会被过滤器拦截@RequestMappin("query")public String userAccount(){return "query";}
}
3.4 字符集过滤器

项目见讲义第1.3.4 - 1.3.5章,项目名为 015-016

CharacterEncodingFilter : 解决post请求中乱码的问题

  • 在SpringMVC框架, 在web.xml 注册过滤器。 配置他的属性。

控制器

public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected 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();}
}

第一种方式:

使用步骤:

  1. 配置字符集过滤器

    @Configuration
    public class WebSystemConfig {//注册Servlet@Beanpublic ServletRegistrationBean servletRegistrationBean(){MyServlet myServlet = new MyServlet();ServletRegistrationBean reg = new ServletRegistrationBean(myServlet,"/myservlet");return reg;}//注册中文编码Filter@Beanpublic 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;}
    }
    
  2. 修改application.properties文件, 让自定义的过滤器起作用

    # SpringBoot中默认已经配置了CharacterEncodingFilter。 编码默认是 ISO-8859-1
    # 设置enabled=false 作用是关闭系统中配置好的过滤器, 使用自定义的CharacterEncodingFilter
    server.servlet.encoding.enabled=false
    

第二种方式:(推荐使用)

使用系统默认的字符集过滤器,需要修改application.properties文件。无需在JavaCofig中注册过滤器

// 使用springBoot中默认的 CharacterEncodingFilterserver.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

第四章 ORM 操作 MySQL

见第4章讲义

使用MyBatis框架操作数据, 在SpringBoot框架集成MyBatis(ORM:对象关系映射)

创建表并插入数据

image-20240309100356711

使用步骤:

  1. mybatis起步依赖:完成mybatis对象自动配置, 这样就将mybatis中用到的对象放在spring容器中

    <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version>
    </dependency>
    
  2. 创建实体类Student

  3. 创建Dao接口 StudentDao , 创建一个通过id查询学生的方法

    创建Dao接口对应的Mapper文件,是一个xml文件, 写对应的sql语句(这里也可以不写mapper文件,直接在Dao接口种使用注解,以及对应的sql语句即可)

  4. 创建Service层对象, 创建StudentService接口和他的实现类。 去调用dao对象的方法,完成数据库的操作

  5. 创建Controller对象,访问Service。

  6. pom.xml 指定把src/main/java目录中的xml文件包含到classpath中(中指定的)

    <!--加入 resource 插件:为了在类路径中找到对应的 Mapper.xml文件-->
    <resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource>
    </resources>
    
  7. 写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
    
  8. 前端请求:http://lcoalhost:8080/myboot/student/query?id=1

@Mapper

项目见讲义第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>
@MapperScan

项目见讲义第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 {
}
Mapper文件和Dao接口分开管理

项目见讲义第1.4.3章,项目名为 018

现在把Mapper文件放在resources目录下

  1. 在resources目录中创建子目录 (自定义的) , 例如mapper

  2. 把XXXmapper.xml 文件放到 mapper目录中

  3. 在application.properties文件中,指定mapper文件的目录

    #指定mapper文件的位置。classpath:表示target/classes目录,编译过后的应用的根路径
    mybatis.mapper-locations=classpath:mapper/*.xml#指定mybatis的日志(此处为控制台输出)
    mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
    
  4. 在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框架中的事务:

  1. 管理事务的对象: 事务管理器(接口, 接口有很多的实现类)

​ 例如:使用Jdbc或mybatis访问数据库,使用的事务管理器:DataSourceTransactionManager

  1. 声明式事务: 在xml配置文件或者使用注解说明事务控制的内容

    ​ 控制事务: 隔离级别,传播行为, 超时时间

  2. 事务处理方式:

​ 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;
}
使用mybits自动生成插件

插件的配置:

GeneratorMapper.xml,插件.txt

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是平级的】

​ 配置好后使用该插件生成代码:

  • maven =》plugins(与lifecycle处于同级)=》mybatis-generator =》mybatis-generator:generate

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中有 讲)

第五章 接口架构风格 —RESTful

接口: API(Application Programming Interface,应用程序接口)是一些预先定义的接口(如函数、HTTP接口),或指软件系统不同组成部分衔接的约定。 用来提供应用程序与开发人员基于某软件或硬件得以访问的一组例程,而又无需访问源码,或理解内部工作机制的细节。

接口(API): 可以指 访问servlet, controller的url, 调用其他程序的函数

架构风格: api组织方式(样子)

就是一个传统的: http://localhost:9002/mytrans/addStudent?name=lisi&age=26

​ 在地址上提供了 访问的资源名称addStudent, 在其后使用了get方式传递参数。

5.1 REST

项目见讲义第1.5章,项目名为 020(对应讲义为1.5.4章)

理论内容可以看这个,实战的话建议看黑马springboot基础篇的项目实战,是一个前后端分离的项目, 采用了RESTful风格(没有涉及到很多东西,只有单表的增删改查)

RESTful架构风格

  1. REST : (英文: Representational State Transfer , 中文: 表现层状态转移)。

    • REST:是一种接口(API)的架构风格和设计的理念,不是标准。
    • 优点: 更简洁,更有层次
    • 表现层状态转移:
      • 表现层就是视图层, 显示资源的。通过视图页面,jsp等等显示操作资源的结果。
      • 状态: 资源变化
      • 转移: 资源可以变化的。 资源能创建,new状态,。 资源创建后可以查询资源, 能看到资源的内容,这个资源内容 ,可以被修改, 修改后资源 和之前的不一样。
  2. REST中的要素:

    • 用REST表示资源和对资源的操作。 在互联网中,表示一个资源或者一个操作。

      • 资源使用url表示的, 在互联网, 使用的图片,视频, 文本,网页等等都是资源。
      • 资源是用名词表示。
    • 对资源的操作:

      ​ 查询资源: 看,通过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

  3. 一句话说明REST:

    • 使用url表示资源 ,使用http动作(请求方式)操作资源。
  4. 注解

    @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

  5. Postman : 测试工具

    使用Postman : 可以测试 get ,post , put ,delete 等请求

案例:

  1. 创建控制器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;}
    
  2. 使用postman测试:

    1. 测试post请求方式创建资源,添加学生信息:http://localhost:8080/myboot/student/zhagnsan/18
5.2 在页面中或者ajax中,支持put,delete请求

项目名 020:testrest.html(对应讲义为1.5.4章)

在SpringMVC中 有一个过滤器, 支持将post请求转为put ,delete请求

  • 过滤器: org.springframework.web.filter.HiddenHttpMethodFilter

  • 作用: 把请求中的post请求转为 put , delete

实现步骤:

  1. application.properties(yml) : 开启使用 HiddenHttpMethodFilter 过滤器

    #  启用支持 put,delete的过滤器    
    spring.mvc.hiddenmethod.filter.enabled=true
    
  2. 在请求页面中,包含 _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>
    
  3. 创建控制器对象

    @PutMapping("/student/test") 
    // @RequestMapping("/student/test", method=RequestMethod.PUT)
    public String test(){return "执行student/test,使用的请求方式 put";
    }
    
  4. 测试put请求

    http://localhost:8080/myboot/student/testrest.html

5.3 请求路径冲突
  • @GetMapping(value = “/student/{studentId}/{classname}”)
  • @GetMapping(value = “/student/{studentId}/{schoolname}”)

这样的路径访问会失败, 路径有冲突。(都是get请求方式,访问的路径还相同,控制器不知道该执行哪个方法)

解决:设计路径,必须唯一。 路径 uri 和 请求方式两者的组合 必须满足唯一性

第六章 Redis

项目见讲义第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的交互

6.1 配置Windows版本的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 客户端的中的方法

导入依赖之后,执行下述操作

  1. 在 application.propertie中指定redis

    #指定 redis
    spring.redis.host=localhost  # 使用的是本机的 redis
    spring.redis.port=6379
    #spring.redis.password=123456
    
  2. 创建控制器对象(添加数据到redis,从redis获取数据)

    @SuppressWarnings({"all"})
    @RestController
    // @RestControllerAdvice  // springboot中的异常处理器(专门用于处理异常信息)
    public class RedisController {/*** 注入 RedisTemplate** RedisTemplate泛型*  1. RedisTemplate<String, String>*  2. RedisTemplate<Object, Object>*  3. RedisTemplate**  注意:RedisTemplate对象的名称为 redisTemplate。(默认的名称:按名称注入)*/@Resourceprivate RedisTemplate redisTemplate;@Resourceprivate 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;}
    }
  3. 使用postman进行测试

    • 添加数据:

      image-20240309133948338

    • 获取数据:

      image-20240309134057299

    • 从redis客户端中也可以得到数据

6.2 对比 StringRedisTemplate 和 RedisTemplate

项目实现步骤见讲义1.6.2章,项目名为 021

​ 需要添加 web的依赖 和 Spring Dat Redis 的依赖

  • StringRedisTemplate
    • 把k,v 都是作为String处理, 使用的是String的序列化 , 可读性好
  • RedisTemplate
    • 把 k,v 经过了序列化存到redis。 k,v 是序列化后的内容, 不能直接识别。默认使用的jdk序列化, 可以修改为其他的序列化

序列化:把对象转化为可传输的字节序列过程称为序列化。(对象 ==》 二进制)

反序列化:把字节序列还原为对象的过程称为反序列化。

为什么需要序列化

**序列化最终的目的是为了对象可以跨平台存储,和进行网络传输。**而我们进行跨平台存储和网络传输的方式就是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);
json序列化

项目名为 021

idea自动生成序列化版本号

在这里插入图片描述

当要为某个类生成序列化版本号时,将光标位于类名,按alt + enter 就有快捷键出现。【序列化要实现接口Serializable】

指定json序列化

使用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;
}
  • 通过postman进行测试

第七章 SpringBoot集成Dubbo(未学)

7.1 Dubbo的文档

https://github.com/apache/dubbo-spring-boot-project/blob/master/README_CN.md

7.2 公共项目

公共接口项目: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);
}
7.3 提供者

服务提供者: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 {@Overridepublic 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);}
}
7.4 消费者

服务提供者: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>
  1. 创建了Controller 或者 Service都可以
@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
调用顺序
  1. 先启动 zookeeper
  2. 启动提供者
  3. 启动消费者
    1. 测试:http://localhost:8080/query?id=1001[springmvc的知识,将id自动传入控制器方法的形参]
7.5 练习

使用的技术: SpringBoot ,Dubbo, Redis, MyBatis

Student表:

image-20210119150418295

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;

  1. 注册学生

​ phone必须唯一, 如果已经存在了手机号, 注册失败的。

​ int addStudent(Student student);

​ 返回值:int

​ 1: 注册成功

​ 2 : 手机号已经存在

​ name至少两个字符,

​ age 必须 大于 0

  1. 查询学生,根据id查询,此学生。

​ 先到redis查询学生, 如果redis没有此学生,从数据库查询, 把查询到的学生放入到redis。

​ 后面再次查询这个学生应该从redis就能获取到。

​ Student queryStudent(Integer id);

  1. 使用Dubbo框架, addStudent, queryStudent 是有服务提供者实现的。

​ 消费者可以是一个Controller , 调用提供者的两个方法。 实现注册和查询。

  1. 页面使用html和ajax,jquery。

​ 在html页面中提供 form 注册学生, 提供文本框输入id,进行查询。

​ 注册和查询都使用ajax技术。

​ html,jquery.js都放到resources/static目录中

第八章 打包

8.1 打包为war

025

1.创建了一个jsp应用(第2.7节:上依赖,上配置)

2.修改pom.xml

  • 加入依赖
  1. 指定打包后的文件名称

    <build><!--打包后的文件名称--><finalName>myboot</finalName>
    </build>
    
  2. 指定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>
    
  3. 执行打包是war

    <!--打包类型-->
    <packaging>war</packaging>
    
  4. 主启动类继承SpringBootServletInitializer

    /*** SpringBootServletInitializer: 继承这个类, 才能使用独立tomcat服务器* SpringBootServletInitializer就是原有的web.xml文件的替代*/
    @SpringBootApplication
    public class JspApplication  extends SpringBootServletInitializer  {public static void main(String[] args) {SpringApplication.run(JspApplication.class, args);}@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(JspApplication.class);}
    }
    
  5. 使用了Maven的插件进行打包(lifecycle中的clean package指令)

    • 打包好的文件放在 target目录下
  6. 部署war

    把war放到tomcat等服务器的发布目录中。 tomcat为例, myboot.war放到tomcat/webapps目录。

war包需发布到服务器才能够运行

8.2 打包为jar

026

  1. 创建了一个包含了jsp的项目(第2.7节:上依赖,上配置)

  2. 修改pom.xml

    • 步骤跟上面差不多(第二步相同)
    1. 指定打包后的文件名称

      <build><!--打包后的文件名称--><finalName>myboot</finalName>
      </build>
      
    2. 指定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>
      
  3. 最后执行 maven clean package

​ 在target目录中,生成jar 文件, 例子是myboot.jar

​ 执行独立的springboot项目 在cmd中 java -jar myboot.jar

jar包双击即可运行(要有jdk环境)

第九章 Thymeleaf 模板引擎(选学)

现在都是前后端分离项目了,这个以后再说。你们随意

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

9.1 表达式
  1. 标准变量表达式

    语法: ${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>
    
  2. 选择变量表达式( 星号变量表达式)

    语法: *{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>
    
  3. 链接表达式

    语法: @{url}

    作用: 表示链接, 可以

     <script src="..."> , <link href="..."> <a href=".."> ,<form action="..."> <img src="...">
    
9.2 Thymeleaf属性

属性是放在html元素中的,就是html元素的属性,加入了th前缀。 属性的作用不变。 加入上th, 属性的值由模板引擎处理了。 在属性可以使用变量表达式

例如:

<form action="/loginServlet" method="post"></form><form th:action="/loginServlet" th:method="${methodAttr}"></form>
9.3 each

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值
9.4 th:if

“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>
9.5 th:switch

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>
9.6 th:inline
  1. 内联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>
    
  2. 内联javascript

    例子:
    <script type="text/javascript" th:inline="javascript">var myname = [[${name}]];var myage = [[${age}]];//alert("获取的模板中数据 "+ myname + ","+myage)function fun(){alert("单击事件,获取数据 "+ myname + ","+ [[${sex}]])}
    </script>
    
9.7 字面量

例子:

<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>
9.8 字符串连接

连接字符串有两种语法

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>
9.9 运算符
算术运 算: + , - - , * , / , %
关系比较 : > , < , >= , <= ( 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的结果三元运算符可以嵌套
9.10 内置对象

文档地址: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>
9.11 内置工具类

内置工具类型: 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>
9.12 自定义模板

模板是内容复用, 定义一次,在其他的模板文件中多次使用。

模板使用:

  1. 定义模板

  2. 使用模板

模板定义语法:

th:fragment="模板自定义名称"例如:
<div th:fragment="head"><p>动力节点-java开发</p><p>www.bjpowernode.com</p>
</div>

引用模板语法:

1) ~{templatename :: selector}templatename:  文件名称selector: 自定义模板名称
2)templatename :: selectortemplatename:  文件名称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, @ComponentScanMyBatis相关的注解@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>
```
9.12 自定义模板

模板是内容复用, 定义一次,在其他的模板文件中多次使用。

模板使用:

  1. 定义模板

  2. 使用模板

模板定义语法:

th:fragment="模板自定义名称"例如:
<div th:fragment="head"><p>动力节点-java开发</p><p>www.bjpowernode.com</p>
</div>

引用模板语法:

1) ~{templatename :: selector}templatename:  文件名称selector: 自定义模板名称
2)templatename :: selectortemplatename:  文件名称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, @ComponentScanMyBatis相关的注解@Mapper : 放在类的上面 , 让MyBatis找到接口, 创建他的代理对象    
@MapperScan :放在主类的上面 , 指定扫描的包, 把这个包中的所有接口都创建代理对象。 对象注入到容器中
@Param : 放在dao接口的方法的形参前面, 作为命名参数使用的。Dubbo注解
@DubboService: 在提供者端使用的,暴露服务的, 放在接口的实现类上面
@DubboReference:  在消费者端使用的, 引用远程服务, 放在属性上面使用。
@EnableDubbo : 放在主类上面, 表示当前引用启用Dubbo功能。

相关文章:

  • fastgpt本地详细部署以及配置
  • Spring boot 集成netty实现websocket通信
  • Android 二维码相关(一)
  • 微信小程序修改placeholder样式
  • Java必须掌握的B树知识点(含面试大厂题含源码)
  • PyTorch搭建LeNet训练集详细实现
  • C语言:内存函数
  • 向ChatGPT高效提问模板
  • DAY by DAY 史上最全的Linux常用命令汇总----命令格式
  • 微信小程序返回上一页刷新组件数据
  • NVMFS5A160PLZT1G汽车级功率MOSFET P沟道60 V 15A 满足AEC-Q101标准
  • 【Logback】Logback 中的 Appenders
  • C#使用Stack<T>类进行堆栈设计
  • Mybatis Plus + Spring 分包配置 ClickHouse 和 Mysql 双数据源
  • 【零基础学习04】嵌入式linux驱动中信号量功能基本实现
  • Google 是如何开发 Web 框架的
  • Golang-长连接-状态推送
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • Node 版本管理
  • Unix命令
  • 三分钟教你同步 Visual Studio Code 设置
  •  一套莫尔斯电报听写、翻译系统
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • ###C语言程序设计-----C语言学习(6)#
  • #QT(串口助手-界面)
  • $().each和$.each的区别
  • (4)事件处理——(7)简单事件(Simple events)
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (六)Hibernate的二级缓存
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (一)基于IDEA的JAVA基础10
  • (转)memcache、redis缓存
  • (转)winform之ListView
  • .net流程开发平台的一些难点(1)
  • .NET设计模式(11):组合模式(Composite Pattern)
  • .Net中的集合
  • @KafkaListener注解详解(一)| 常用参数详解
  • [2019/05/17]解决springboot测试List接口时JSON传参异常
  • [AIGC] 开源流程引擎哪个好,如何选型?
  • [android学习笔记]学习jni编程
  • [Angular] 笔记 16:模板驱动表单 - 选择框与选项
  • [autojs]逍遥模拟器和vscode对接
  • [BZOJ1089][SCOI2003]严格n元树(递推+高精度)
  • [codeforces]Checkpoints
  • [cogs2652]秘术「天文密葬法」
  • [HackMyVM]靶场 Quick3
  • [IE编程] IE中使网页元素进入编辑模式
  • [Java]快速入门优先队列(堆)手撕相关面试题