第十二章 微服务核心(一)
一、Spring Boot
1.1 SpringBoot 构建方式
1.1.1 通过官网自动生成
1.1.2 IDE 在线模板生成
1.1.3 IDE 通过 Maven 项目构建
2.1.1 创建 Maven 项目
2.1.2 添加依赖
<!-- 1.添加SpringBoot的依赖 --><parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version>2.3.2.RELEASE</version></parent><dependencies><!-- 2.添加SpringMVC的支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>
2.1.3 创建启动类
/*** SpringBoot 项目的启动类*/
@SpringBootApplication
public class AppStart {public static void main(String[] args) {SpringApplication.run(AppStart.class, args);}
}
2.1.4 启动程序
1.2 SpringBoot 中的常规配置
1.2.1 入口类和相关注解
@SpringBootApplication
public class SpringMybatisGenertorApplication {public static void main(String[] args) {SpringApplication.run(SpringMybatisGenertorApplication.class, args);}}
@Target({ElementType.TYPE}) // 注解可以写在哪些地方
@Retention(RetentionPolicy.RUNTIME) // 该注解的作用域 RESOURCES CLASS RUNTIME
@Documented // 该注解会被API抽取
@Inherited // 可继承
// 以上四个是Java中提供的元注解
@SpringBootConfiguration // 本质上就是一个Configuration注解
@EnableAutoConfiguration // 自动装配的注解
@ComponentScan( // 扫描 会自动扫描 @SpringBootApplication所在的类的同级包(com.gupaoedu)以及子包中的Bean,所有一般我们建议将入口类放置在 groupId+artifcatID的组合包下excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}
)
1.2.2 常规配置
server.port=8082server.servlet.context-path=/springboot
user.userName=adminuser.realName=零一user.address=湖南长沙
@RestControllerpublic class HelloController {@Value(value = "${user.userName}")private String userName;@Value(value = "${user.realName}")private String realName;@Value(value = "${user.address}")private String address;@RequestMapping("/hello")public String hello() {System.out.println("Hello ..." + userName + " " + realName + " " + address);return "Hello ...";}}
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.messages.encoding=UTF-8
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency>
package com.gupaoedu.bean;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;@Component// 属性文件中的属性和User对象中的成员变量映射@ConfigurationProperties(prefix = "user")public class User {private String username;private Integer age;private String address;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", age=" + age +", address='" + address + '\'' +'}';}}
1.2.3 Logback 日志
# logback的配置
logging.file=d:/log.log
logging.level.org.springframework.web=DEBUG
1.2.4 Profile
1.3 SpringBoot 中的静态资源
1.3.1 static 目录
1.3.2 webapp 目录
1.3.3 自定义静态资源路径
1.4 SpringBoot 自动装配
1.4.1 @EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}
1.4.2 @Import
> 1.基于xml配置文件<bean>
>
> 2.基于xml配置文件@Component
>
> 3.基于Java配置类【@Configuration】 @Bean
>
> 4.基于Java配置类+@ComponentScan+@Component
>
> 5.FactoryBean接口【getObject()】
>
> 6.@Import注解
@Configuration
@Import(UserService.class)
public class JavaConfig {/*@Beanpublic UserService getUserSerivce(){return new UserService();}*/
}
public class GpImportSelector implements ImportSelector {/*** 动态获取IoC要加载的类型* @param annotationMetadata 注解的元数据* @return* IoC要加载的类型的数组*/@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {// 根据不同的业务逻辑 实现动态添加IoC加载的类型/*if (){}*/return new String[]{LoggerService.class.getName(),CacheService.class.getName()};}
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(GpImportSelector.class)
public @interface EnableGpImport {
}import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;@EnableGpImport
public class ImportMain {public static void main(String[] args) {ApplicationContext ac = new AnnotationConfigApplicationContext(ImportMain.class);String[] beanDefinitionNames = ac.getBeanDefinitionNames();for (String beanName : beanDefinitionNames){System.out.println(beanName);}}
}
public class GpImportBeanDefinition implements ImportBeanDefinitionRegistrar {/*** 提供了一个beanDefinition的注册器,我直接把需要IoC加载的类型注册到容器中去* @param annotationMetadata* @param beanDefinitionRegistry beanDefinition的注册器*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {// 将我们需要添加的类型统一封装为RootBeanDefinition对象RootBeanDefinition cache = new RootBeanDefinition(CacheService.class);beanDefinitionRegistry.registerBeanDefinition("cache",cache);RootBeanDefinition logger = new RootBeanDefinition(LoggerService.class);beanDefinitionRegistry.registerBeanDefinition("logger",logger);}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;@EnableGpImport
public class ImportMain {public static void main(String[] args) {ApplicationContext ac = new AnnotationConfigApplicationContext(ImportMain.class);String[] beanDefinitionNames = ac.getBeanDefinitionNames();for (String beanName : beanDefinitionNames){System.out.println(beanName);}}
}
1.4.3 自动装配的原理
1.5 SpringBoot 整合 Servlet
1.5.1 第一种方式
1. 添加自定义的 Servlet
package com.gupaoedu.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet(name = "FirstServlet",urlPatterns = "/first")
public class FirstServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("FirstServlet running ... ");PrintWriter out = resp.getWriter();out.write("success ... ");out.flush();out.close();}
}
2. 在启动类中添加扫描注解
package com.gupaoedu;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {public static void main(String[] args) {SpringApplication.run(GpSpringbootDemo05Application.class, args);}}
1.5.2 第二种方式
1. 创建自定义的 Servlet,不需要添加@WebServlet
package com.gupaoedu.servlet;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;public class SecondServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("SecondServlet running ... ");PrintWriter out = resp.getWriter();out.write("success ... ");out.flush();out.close();}
}
2. 在启动类中显示在注册
package com.gupaoedu;import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {public static void main(String[] args) {SpringApplication.run(GpSpringbootDemo05Application.class, args);}@Beanpublic ServletRegistrationBean getRegistrationBean(){// 将要添加的Servlet封装为一个ServletRegistrationBean对象ServletRegistrationBean registrationBean = new ServletRegistrationBean(new SecondServlet());// 设置映射信息registrationBean.addUrlMappings("/second");return registrationBean;}
}
1.6 SpringBoot 整合 Filter
1.6.1 第一种方式
1. 直接在过滤器中添加@WebFilter 注解
package com.gupaoedu.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;@WebFilter(urlPatterns = "/first")
public class FirstFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("----init----");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("________First过滤器执行之前_________");filterChain.doFilter(servletRequest,servletResponse);System.out.println("________First过滤器执行之后_________");}@Overridepublic void destroy() {System.out.println("****destroy****");}
}
2. 在启动器中添加@ServletCompoenentScan
package com.gupaoedu;import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {public static void main(String[] args) {SpringApplication.run(GpSpringbootDemo05Application.class, args);}
}
1.6.2 第二种方式
1. 创建自定义的过滤器,不需要添加@WebFilter 注解。
package com.gupaoedu.filter;import javax.servlet.*;
import java.io.IOException;public class SecondFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("--second--init----");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("________Second过滤器执行之前_________");filterChain.doFilter(servletRequest,servletResponse);System.out.println("________Second过滤器执行之后_________");}@Overridepublic void destroy() {System.out.println("****destroy****");}
}
2. 在启动类中显示的注册
package com.gupaoedu;import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {public static void main(String[] args) {SpringApplication.run(GpSpringbootDemo05Application.class, args);}@Beanpublic FilterRegistrationBean getRegistractionBean(){FilterRegistrationBean bean = new FilterRegistrationBean(new SecondFilter());bean.addUrlPatterns("/second");return bean;}
}
1.7 SpringBoot 整合 Listener
1.7.1 第一种方式
1. 创建自定义的 Listener
package com.gupaoedu.listener;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;@WebListener
public class FirstListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("FirstListener : 初始化了....");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("FirstListener : 销毁了....");}
}
2. 添加扫描注解
package com.gupaoedu;import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {public static void main(String[] args) {SpringApplication.run(GpSpringbootDemo05Application.class, args);}
}
1.7.2 第二种方式
1. 创建自定义 Listener
package com.gupaoedu.listener;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;public class SecondListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("SecondListener : 初始化了....");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("SecondListener : 销毁了....");}
}
2. 显示的在启动类中注册
package com.gupaoedu;import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {public static void main(String[] args) {SpringApplication.run(GpSpringbootDemo05Application.class, args);}@Beanpublic ServletListenerRegistrationBean getListenerRegistrationBean(){ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean(new SecondListener());return bean;}
}
1.8 SpringBoot 整合 Freemarker
1.8.1 添加对应的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
1.8.2 添加一个自定义的控制器
package com.gupaoedu.controller;import com.gupaoedu.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.ArrayList;
import java.util.List;@Controller
public class UserController {@RequestMapping("/showUser")public String showUser(Model model){List<User> list = new ArrayList<>();list.add(new User(1,"zhangsan",22));list.add(new User(2,"lisi",23));list.add(new User(3,"wangwu",24));model.addAttribute("list",list);return "user";}
}
1.8.3 属性文件配置
1.8.4 ftl 模板页面
<html><head><title>用户信息</title><meta charset="UTF-8"></head><body><table border="1" align="center" width="50%"><tr><th>ID</th><th>姓名</th><th>年龄</th></tr><#list list as user><tr><td>${user.id}</td><td>${user.userName}</td><td>${user.age}</td></tr></#list></table></body>
</html>
1.9 SpringBoot 整合 Thymeleaf
1.9.1 添加相关的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
1.9.2 创建自定义的控制器
package com.gupaoedu.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class UserController {@RequestMapping("/show")public String showInfo(Model model){model.addAttribute("msg","Thymeleaf Hello ....");return "index";}
}
1.9.3 创建对应的模板页面
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>Thymeleaf整合</h1><hr><span th:text="${msg}"></span>
</body>
</html>
1.10 SpringBoot 实现热部署操作
1.10.1 打开配置
1.10.2 按下快捷键【ctrl+shift+alt+'/'】
1.10.3 添加 spring-boot-devtools 依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId>
</dependency><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><fork>true</fork></configuration></plugin></plugins>
</build>
1.11 SpringBoot 中的异常处理
1.11.1 自定义错误页面
1.11.2 @ExceptionHandler 处理
package com.gupaoedu.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.validation.constraints.Null;@Controller
public class UserController {@RequestMapping("/show1")public String showInfo1(){String msg = null;msg.length(); // NullPointerExceptionreturn "success";}/*** 如果当前类中出现了NullPointerException异常就会跳转到本方法对应的view中* @return*/@ExceptionHandler(value = {NullPointerException.class})public ModelAndView nullPointerExceptionHandler(Exception e){ModelAndView view = new ModelAndView();view.addObject("error",e.toString());view.setViewName("error1");return view;}/*** 如果当前类中出现了ArithmeticException异常就会跳转到本方法对应的view中* @return*/@ExceptionHandler(value = {ArithmeticException.class})public ModelAndView arithmeticExceptionHandler(Exception e){ModelAndView view = new ModelAndView();view.addObject("error",e.toString());view.setViewName("error2");return view;}@RequestMapping("/show2")public String showInfo2(){int i = 0;int b = 100;System.out.println(b/i); // ArithmeicExpetionreturn "success";}}
1.11.3 @ControllerAdvice 处理
package com.gupaoedu.handler;import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;@ControllerAdvice
public class GlobalException {/*** 如果当前类中出现了NullPointerException异常就会跳转到本方法对应的view中* @return*/@ExceptionHandler(value = {NullPointerException.class})public ModelAndView nullPointerExceptionHandler(Exception e){ModelAndView view = new ModelAndView();view.addObject("error",e.toString());view.setViewName("error1");return view;}/*** 如果当前类中出现了ArithmeticException异常就会跳转到本方法对应的view中* @return*/@ExceptionHandler(value = {ArithmeticException.class})public ModelAndView arithmeticExceptionHandler(Exception e){ModelAndView view = new ModelAndView();view.addObject("error",e.toString());view.setViewName("error2");return view;}
}
1.11.4 SimpleMappingExceptionResolver 处理
package com.gupaoedu;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.Properties;@SpringBootApplication
public class GpSpringbootDemo08ThymeleafApplication {public static void main(String[] args) {SpringApplication.run(GpSpringbootDemo08ThymeleafApplication.class, args);}/*** 异常信息和对应的 处理地址的 映射* @return*/@Beanpublic SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){SimpleMappingExceptionResolver mapping = new SimpleMappingExceptionResolver();Properties mappings = new Properties();mappings.setProperty("java.lang.NullPointerException","error1");mappings.setProperty("java.lang.ArithmeticException","error2");mapping.setExceptionMappings(mappings);return mapping;}
}
1.11.5 自定义 HandlerExceptionResolver
package com.gupaoedu.handler;import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {/*** 自定义的全局异常* @param httpServletRequest* @param httpServletResponse* @param o* @param e* @return*/@Overridepublic ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {System.out.println("全局的自定义异常处理触发了....");ModelAndView mv = new ModelAndView();if(e instanceof NullPointerException){mv.setViewName("error1");mv.addObject("error","空指针异常");}else if(e instanceof ArithmeticException){mv.setViewName("error2");mv.addObject("error","算数异常");}return mv;}
}
1.12 SpringBoot 中的单元测试
1.12.1 添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
1.12.2 单元测试
1.13 SpringBoot 整合 MyBatis
1.13.1 添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.gupaoedu</groupId><artifactId>gp_springboot_mybatis_demo</artifactId><version>1.0-SNAPSHOT</version><!-- 配置依赖的父类 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.5.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.14</version></dependency></dependencies></project>
1.13.2 配置文件
# jdbc的相关配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456# 连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource## mybatis的package别名
mybatis.type-aliases-package=com.gupaoedu.pojo# 指定MyBatis的映射文件的路径
mybatis.mapper-locations=classpath:mapper/*.xml
1.13.3 启动器
package com.gupaoedu;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class StartApp {public static void main(String[] args) {SpringApplication.run(StartApp.class,args);}
}
1.13.4 数据库表结构
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL, PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.13.5 创建对应的 Pojo 对象
package com.gupaoedu.pojo;public class User {private Integer id;private String name;private Integer age;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}
}
1.13.6 mapper 接口
package com.gupaoedu.mapper;import com.gupaoedu.pojo.User;
import java.util.List;public interface UserMapper {public List<User> query(User user);public Integer addUser(User user);/*** 根据id查询用户信息* @param id* @return*/public User queryById(Integer id);public Integer deleteUserById(Integer id);public Integer updateUser(User user);
}
1.13.7 mapper 映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gupaoedu.mapper.UserMapper"><select id="query" resultType="User">select * from users</select><insert id="addUser" parameterType="User">INSERT INTO users (name,age)VALUES(#{name},#{age})</insert><select id="queryById" resultType="User" >select * from users where id = #{id}</select><update id="updateUser" parameterType="User">update users set name=#{name},age=#{age} where id =#{id}</update><delete id="deleteUserById" >delete from users where id = #{id}</delete>
</mapper>
1.13.8 Service 接口
package com.gupaoedu.service;import com.gupaoedu.pojo.User;
import java.util.List;public interface IUserService {public List<User> query(User user);public Integer addUser(User user);/*** 根据id查询用户信息* @param id* @return*/public User queryById(Integer id);public Integer updateUser(User user);public Integer deleteUserById(Integer id);
}
1.13.9 Service 实现类
package com.gupaoedu.service.impl;import com.gupaoedu.mapper.UserMapper;
import com.gupaoedu.pojo.User;
import com.gupaoedu.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;@Service
@Transactional
public class UserServiceImpl implements IUserService {@Autowiredprivate UserMapper mapper;@Overridepublic List<User> query(User user) {return mapper.query(user);}@Overridepublic Integer addUser(User user) {return mapper.addUser(user);}@Overridepublic User queryById(Integer id) {return mapper.queryById(id);}@Overridepublic Integer updateUser(User user) {return mapper.updateUser(user);}@Overridepublic Integer deleteUserById(Integer id) {return mapper.deleteUserById(id);}
}
1.13.10 controller
package com.gupaoedu.controller;import com.gupaoedu.pojo.User;
import com.gupaoedu.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;@Controller
public class UserController {@Autowiredprivate IUserService service;/*** 基础页面的请求* @param page* @return*/@RequestMapping("/{page}")public String showPage(@PathVariable String page){return page;}@RequestMapping("/user/query")public String query(Model model){model.addAttribute("list",service.query(null));return "user";}@RequestMapping("/user/save")public String addUser(User user){service.addUser(user);return "redirect:/user/query";}@RequestMapping("/user/updateInfo")public String updateInfo(Integer id,Model model){User user = service.queryById(id);model.addAttribute("user",user);return "updateUser";}@RequestMapping("/user/deleteUser")public String deleteUser(Integer id){service.deleteUserById(id);return "redirect:/user/query";}@RequestMapping("/user/update")public String updateUser(User user){service.updateUser(user);return "redirect:/user/query";}
}
1.13.11 启动类添加 Mapper 扫描路径
package com.gupaoedu;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.gupaoedu.mapper") // 用户扫描Mapper接口
public class StartApp {public static void main(String[] args) {SpringApplication.run(StartApp.class,args);}
}
1.13.12 用户信息查询
@Controller
public class UserController {@Autowiredprivate IUserService service;@RequestMapping("/user/query")public String query(Model model){model.addAttribute("list",service.query(null));return "user";}
}
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>用户信息</title>
</head>
<body><h1>用户管理</h1><table border="1" style="width: 300px"><tr><th>用户ID</th><th>用户姓名</th><th>用户年龄</th></tr><tr th:each="user:${list}"><td th:text="${user.id}"></td><td th:text="${user.name}"></td><td th:text="${user.age}"></td></tr></table>
</body>
</html>
1.13.13 用户信息添加
public interface UserMapper {public List<User> query(User user);public Integer addUser(User user);
}
<insert id="addUser" parameterType="User">INSERT INTO users (name,age)VALUES(#{name},#{age})
</insert>service接口public interface IUserService {public List<User> query(User user);public Integer addUser(User user);
}
@Service
@Transactional
public class UserServiceImpl implements IUserService {@Autowiredprivate UserMapper mapper;@Overridepublic List<User> query(User user) {return mapper.query(user);}@Overridepublic Integer addUser(User user) {return mapper.addUser(user);}
}
@Controller
public class UserController {@Autowiredprivate IUserService service;@RequestMapping("/user/query")public String query(Model model){model.addAttribute("list",service.query(null));return "user";}@RequestMapping("/user/save")public String addUser(User user){service.addUser(user);return "redirect:/user/query";}
}
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><title>用户信息</title></head><body><h1>添加用户</h1><form th:action="@{/user/save}" method="post"><label>姓名:</label><input type="text" name="name"><br><label>年龄:</label><input type="text" name="age"><br><input type="submit" value="提交"></form></body>
</html>
/*** 基础页面的请求* @param page* @return*/
@RequestMapping("/{page}")
public String showPage(@PathVariable String page){return page;
}
1.13.14 用户信息修改
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>用户信息</title>
</head>
<body><h1>用户管理</h1><table border="1" style="width: 300px"><tr><th>用户ID</th><th>用户姓名</th><th>用户年龄</th><th>操作</th></tr><tr th:each="user:${list}"><td th:text="${user.id}"></td><td th:text="${user.name}"></td><td th:text="${user.age}"></td><td><a th:href="@{/user/updateInfo(id=${user.id})}">修改</a></td></tr></table>
</body>
</html>
package com.gupaoedu.mapper;import com.gupaoedu.pojo.User;
import java.util.List;public interface UserMapper {public List<User> query(User user);public Integer addUser(User user);/*** 根据id查询用户信息* @param id* @return*/public User queryById(Integer id);public Integer updateUser(User user);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gupaoedu.mapper.UserMapper"><select id="query" resultType="User">select * from users</select><insert id="addUser" parameterType="User">INSERT INTO users (name,age)VALUES(#{name},#{age})</insert><select id="queryById" resultType="User" >select * from users where id = #{id}</select><update id="updateUser" parameterType="User">update users set name=#{name},age=#{age} where id =#{id}</update>
</mapper>
package com.gupaoedu.controller;import com.gupaoedu.pojo.User;
import com.gupaoedu.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;@Controller
public class UserController {@Autowiredprivate IUserService service;/*** 基础页面的请求* @param page* @return*/@RequestMapping("/{page}")public String showPage(@PathVariable String page){return page;}@RequestMapping("/user/query")public String query(Model model){model.addAttribute("list",service.query(null));return "user";}@RequestMapping("/user/save")public String addUser(User user){service.addUser(user);return "redirect:/user/query";}@RequestMapping("/user/updateInfo")public String updateInfo(Integer id,Model model){User user = service.queryById(id);model.addAttribute("user",user);return "updateUser";}@RequestMapping("/user/update")public String updateUser(User user){service.updateUser(user);return "redirect:/user/query";}
}
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><title>用户信息</title></head><body><h1>更新用户</h1><form th:action="@{/user/update}" method="post"><input type="hidden" name="id" th:value="${user.id}"><label>姓名:</label><input type="text" name="name" th:value="${user.name}"><br><label>年龄:</label><input type="text" name="age" th:value="${user.age}"><br><input type="submit" value="提交"></form></body>
</html>
1.13. 15 用户信息删除
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>用户信息</title>
</head>
<body><h1>用户管理</h1><table border="1" style="width: 300px"><tr><th>用户ID</th><th>用户姓名</th><th>用户年龄</th><th>操作</th></tr><tr th:each="user:${list}"><td th:text="${user.id}"></td><td th:text="${user.name}"></td><td th:text="${user.age}"></td><td><a th:href="@{/user/updateInfo(id=${user.id})}">修改</a><a th:href="@{/user/deleteUser(id=${user.id})}">删除</a></td></tr></table>
</body>
</html>
@RequestMapping("/user/deleteUser")
public String deleteUser(Integer id){service.deleteUserById(id);return "redirect:/user/query";
}
1.14 SpringBoot 整合 Shiro
1.14.1 表结构
CREATE TABLE `t_user` (`id` int(20) NOT NULL AUTO_INCREMENT,`username` varchar(20) DEFAULT NULL,`password` varchar(100) DEFAULT NULL,`salt` varchar(100) DEFAULT NULL,`create_time` datetime DEFAULT NULL,`state` int(1) DEFAULT NULL,`last_login_time` datetime DEFAULT NULL,`nickname` varchar(30) DEFAULT NULL,`realname` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
1.14.2 添加依赖
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.3.2</version>
</dependency>
1.14.3 自定义的 realm
package com.gupaoedu.realm;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;public class AuthcRealm extends AuthorizingRealm {/*** 认证的方法* @param authenticationToken* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {return null;}/*** 授权的方法* @param principalCollection* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}
}
1.14.4 Shiro 的配置类
package com.gupaoedu.config;import com.gupaoedu.realm.AuthcRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.HashMap;
import java.util.Map;@Configuration
public class ShiroConfig {// 散列算法private String hashAlgorithmName = "md5";// 迭代次数private Integer hashIterations = 1024;/*** 获取凭证匹配器* @return*/@Beanpublic HashedCredentialsMatcher hashedCredentialsMatcher(){HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();matcher.setHashAlgorithmName(hashAlgorithmName);matcher.setHashIterations(hashIterations);return matcher;}/*** 获取自定义的Realm* @return*/@Beanpublic AuthcRealm authcRealm(HashedCredentialsMatcher matcher){AuthcRealm realm = new AuthcRealm();realm.setCredentialsMatcher(matcher);return realm;}/*** 获取SecurityManager对象* @param realm* @return*/@Beanpublic SecurityManager securityManager(AuthcRealm realm){DefaultWebSecurityManager manager = new DefaultWebSecurityManager();manager.setRealm(realm);return manager;}/*** 注册ShiroFilterFactoryBean* @param manager* @return*/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager manager){ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();filter.setSecurityManager(manager);filter.setLoginUrl("/login.do");filter.setSuccessUrl("/success.html");filter.setUnauthorizedUrl("/refuse.html");// 设置过滤器链Map<String,String> map = new HashMap<>();map.put("/css/*","anon");map.put("/js/**","anon");map.put("/img/**","anon");map.put("/js/**","anon");map.put("/login","anon");map.put("/login.do","authc");map.put("/**","authc");filter.setFilterChainDefinitionMap(map);return filter;}
}
1.14.5 认证配置
package com.gupaoedu.realm;import com.gupaoedu.pojo.User;
import com.gupaoedu.service.IUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.SimpleByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;public class AuthcRealm extends AuthorizingRealm {@Autowiredprivate IUserService service;/*** 认证的方法* @param authenticationToken* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String userName = token.getUsername();System.out.println("开始认证:" + userName);User user = new User();user.setUsername(userName);// 根据账号认证List<User> list = service.query(user);if(list == null || list.size() != 1){// 账号不存在或者异常return null;}user = list.get(0);return new SimpleAuthenticationInfo(user,user.getPassword() // 密码,new SimpleByteSource(user.getSalt()) // salt,"authcRealm" // 自定义的Realm名称);}/*** 授权的方法* @param principalCollection* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}
}
1.14.6 控制器
package com.gupaoedu.controller;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;@Controller
public class AuthcController {@RequestMapping("/login.do")public String login(HttpServletRequest request){// 认证失败的异常信息Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);System.out.println("认证失败的信息:" + obj);return "login";}@RequestMapping("/logout.do")public String logout(){SecurityUtils.getSubject().logout();return "redirect:/login";}
}
1.14.7 登录界面
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>登录管理</h1><form th:action="/login.do" method="post"><label>账号:</label><input type="text" name="username"><br><label>密码:</label><input type="password" name="password"><br><input type="submit" value="提交"></form>
</body>
</html>
1.15 SpringBoot 整合 SpringSecurity
1.15.1 添加 SpringSecurity 的依赖即可
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
1.15.2 重启访问即可跳转到对应的登录界面
1.15.3 自定义登录界面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录</title>
</head>
<body>
<h2>自定义登录页面</h2>
<form action="/authentication/form" method="post"><table><tr><td>用户名:</td><td><input type="text" name="username"></td></tr><tr><td>密码:</td><td><input type="password" name="password"></td></tr><tr><td colspan="2"><button type="submit">登录</button></td></tr></table>
</form>
</body>
</html>
1.15.4 自定义 SpringSecurity 的配置类
package com.gupaoedu.config;import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@Configuration
@EnableWebSecurity // 方法SpringSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 认证的配置* @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 配置自定义的账号密码auth.inMemoryAuthentication().withUser("zhang").password("{noop}123").roles("USER");// 用户具有的角色}/*** http请求的配置* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin().loginPage("/login.html") // 指定自定义的登录界面.loginProcessingUrl("/login.do") // 必须和登录表单的 action一致.and().authorizeRequests() // 定义哪些资源被保护.antMatchers("/login.html").permitAll() // login.html可以匿名访问.anyRequest().authenticated(); //出来登录页面其他都需要认证http.csrf().disable();// 禁用跨越攻击}
}
1.15.5 数据库认证
public interface UserService extends UserDetailsService {
}
1.15.6 service 实现中冲 load***方法
package com.gupaoedu.service.impl;import com.gupaoedu.service.UserService;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;@Service
public class UserServiceImpl implements UserService {@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 模拟数据库操作 根据账号查询String password = "456";// 假设查询出来的用户的角色List<SimpleGrantedAuthority> list = new ArrayList<>();list.add(new SimpleGrantedAuthority("USER1"));UserDetails userDetails = new User(s,"{noop}"+password,list);return userDetails;}
}
1.15.7 在 SpringSecurity 的配置类添加配置信息
package com.gupaoedu.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;@Configuration
@EnableWebSecurity // 方法SpringSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;/*** 认证的配置* @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 配置自定义的账号密码/*auth.inMemoryAuthentication().withUser("zhang").password("{noop}123").roles("USER");// 用户具有的角色*/// 关联自定义的认证的Serviceauth.userDetailsService(userDetailsService);}/*** http请求的配置* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin().loginPage("/login.html") // 指定自定义的登录界面.loginProcessingUrl("/login.do") // 必须和登录表单的 action一致.and().authorizeRequests() // 定义哪些资源被保护.antMatchers("/login.html").permitAll() // login.html可以匿名访问.anyRequest().authenticated(); //出来登录页面其他都需要认证http.csrf().disable();// 禁用跨越攻击}
}
1.15.8 加密认证
@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 配置自定义的账号密码/*auth.inMemoryAuthentication().withUser("zhang").password("{noop}123").roles("USER");// 用户具有的角色*/// 关联自定义的认证的Serviceauth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());}
1.15.9 在 service 获取对应的加密的密文
package com.gupaoedu.service.impl;import com.gupaoedu.service.UserService;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Service
public class UserServiceImpl implements UserService {@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 模拟数据库操作 根据账号查询String password = "$2a$10$9tzTU0L5cM7e25RPo.KGnOfzUzeulD0CzOoawooYSiUlrPABkCPXG";// 假设查询出来的用户的角色List<SimpleGrantedAuthority> list = new ArrayList<>();list.add(new SimpleGrantedAuthority("USER1"));UserDetails userDetails = new User(s,password,list);return userDetails;}
}
1.16 SpringBoot 整合 Ehcache
1.16.1 添加依赖
<dependency><groupId>error</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId>
</dependency>
1.16.2 添加 Ehcache 的配置
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"updateCheck="false"><diskStore path="java.io.tmpdir"/><!--defaultCache:echcache 的默认缓存策略 --><defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"maxElementsOnDisk="10000000"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"><persistence strategy="localTempSwap"/></defaultCache><!-- 自定义缓存策略 --><cache name="users"maxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"maxElementsOnDisk="10000000"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"><persistence strategy="localTempSwap"/></cache>
</ehcache>
1.16.3 在 application.properties 中关联 Ehcache 的配置文件
1.16.4 在需要开启换的位置通过 Cacheable 设置
1.16.5 单元测试,放开缓存
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>
</dependency>
package com.gupaoedu.test;import com.gupaoedu.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest
@EnableCaching// 放开缓存
public class Test01 {@Autowiredprivate IUserService userService;@Testpublic void test01(){userService.queryById(1);userService.queryById(1);}
}
1.17 SpringBoot 整合 SpringDataRedis
1.17.1 添加相关的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version>
</dependency>
1.17.2 配置信息
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=5
spring.redis.jedis.pool.max-active=20
spring.redis.host=192.168.187.120
spring.redis.port=6379
1.17.3 Redis 的配置类
package com.gupaoedu.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;@Configuration
public class RedisConfig {/*** 创建JedisPoolConfig对象* @return*/@Bean@ConfigurationProperties(prefix = "spring.redis.pool")public JedisPoolConfig jedisPoolConfig(){JedisPoolConfig config = new JedisPoolConfig();System.out.println("默认值:" + config.getMaxIdle());System.out.println("默认值:" + config.getMinIdle());System.out.println("默认值:" + config.getMaxTotal());return config;}@Bean@ConfigurationProperties(prefix = "spring.redis.pool")public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig config){JedisConnectionFactory factory = new JedisConnectionFactory();factory.setPoolConfig(config);return factory;}@Beanpublic RedisTemplate<String,Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory){RedisTemplate<String,Object> template = new RedisTemplate<>();template.setConnectionFactory(jedisConnectionFactory);// 设置 key的序列号器template.setKeySerializer(new StringRedisSerializer());// 设置 value的序列化器template.setValueSerializer(new StringRedisSerializer());return template;}
}
1.17.4 单元测试
package com.gupaoedu;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;@RunWith(SpringRunner.class)
@SpringBootTest
public class GpSpringbootRedisDemoApplicationTests {@Autowiredprivate RedisTemplate<String,Object> template;/*** 添加一个简单的字符串*/@Testpublic void test01() {this.template.opsForValue().set("name","bobo");}}
package com.gupaoedu;import com.gupaoedu.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;@RunWith(SpringRunner.class)
@SpringBootTest
public class GpSpringbootRedisDemoApplicationTests {@Autowiredprivate RedisTemplate<String,Object> template;/*** 添加一个简单的字符串*/@Testpublic void test01() {this.template.opsForValue().set("name","bobo");}@Testpublic void test02() {System.out.println(template.opsForValue().get("name"));}/*** 将User对象序列化为一个字符串存储*/@Testpublic void test03(){User user = new User(1,"张三","湖南长沙");// 设置序列化器template.setValueSerializer(new JdkSerializationRedisSerializer());template.opsForValue().set("user",user);}/*** 将Redis中存储的User对象反序列化出来*/@Testpublic void test04(){template.setValueSerializer(new JdkSerializationRedisSerializer());User user = (User) this.template.opsForValue().get("user");System.out.println(user);}/*** 将User对象转换为JSON对象存储*/@Testpublic void test05(){User user = new User(2,"李四","湖南长沙");template.setValueSerializer(new Jackson2JsonRedisSerializer<>(User.class));template.opsForValue().set("userJson",user);}/*** 将Redis中存储的JSON数据取出转换为User对象*/@Testpublic void test06(){template.setValueSerializer(new Jackson2JsonRedisSerializer<>(User.class));User user = (User) template.opsForValue().get("userJson");System.out.println(user);}}
1.18 SpringBoot 整合 Scheduled
1.18.1 添加相关的依赖
<!-- 添加 Scheduled 坐标 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>5.1.7.RELEASE</version></dependency>
1.18.2 创建定时任务的方法
package com.gupaoedu.task;import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;@Component
public class MyScheduledTask {/*** 定时任务的方法*/@Scheduled(cron = "0/2 * * * * ?")public void doSome(){System.out.println("定时任务执行了...." + new Date());}
}
1.18.3 在启动器中放开 Scheduled
@SpringBootApplication
@EnableScheduling // 放开Scheduled定时任务
public class GpSpringbootScheduledDemoApplication {public static void main(String[] args) {SpringApplication.run(GpSpringbootScheduledDemoApplication.class, args);}}
>
>@Scheduled(cron = “0 0 1 1 1,6 ?”) //一月和六月的一号的 1:00:00 执行一次
>
>@Scheduled(cron = “0 0 1 1 1,4,7,10 ?”) //每个季度的第一个月的一号的 1:00:00 执行一次
>
>@Scheduled(cron = “0 0 1 1 * ?”)//每月一号 1:00:00 执行一次
>
>@Scheduled(cron=“0 0 1 * * *”) //每天凌晨 1 点执行一次
1.19 SpringBoot 整合 Quartz
| 组成 | 描述 |
| ------------------- | ---------------------------- |
| Job--任务 | 你要做什么事? |
| Trigger--触发器 | 你什么时候去做? |
| Scheduler--任务调度 | 你什么时候需要去做什么事情? |
1.19.1 Quartz 基本使用
1. 依赖
<!-- Quartz 坐标 -->
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.1</version>
</dependency>
2. 创建 Job
package com.gupaoedu.Job;import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;public class MyJob implements Job {/*** 自定义的Job* @param jobExecutionContext* @throws JobExecutionException*/@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("quartz任务执行了..." + new Date());}
}
3. 测试
package com.gupaoedu.Job;import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;public class JobMain {public static void main(String[] args) throws SchedulerException {// 1.创建Job对象JobDetail job = JobBuilder.newJob(MyJob.class).build();// 2.创建TriggerTrigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")).build();// 3.创建Scheduler对象Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();scheduler.scheduleJob(job,trigger);// 启动scheduler.start();}
}
1.19.2 SpringBoot 整合 Quartz
1. 添加对应的依赖
<!-- Quartz 坐标 --><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.1</version><exclusions><exclusion><artifactId>slf4j-api</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency><!-- 添加 Scheduled 坐标 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId></dependency><!-- Sprng tx 坐标 --><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId></dependency>
2. 创建对应的 Quartz 配置类
package com.gupaoedu.config;import com.gupaoedu.Job.MyJob;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;@Configuration
public class QuartzConfig {/*** 创建Job对象* @return*/@Beanpublic JobDetailFactoryBean jobDetailFactoryBean(){JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();// 关联 Job类factoryBean.setJobClass(MyJob.class);return factoryBean;}/*** 创建Trigger对象* @return*/@Beanpublic SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();// 关联JobDetail对象factoryBean.setJobDetail(jobDetailFactoryBean.getObject());// 设置间隔时间factoryBean.setRepeatInterval(2000);// 设置重复次数factoryBean.setRepeatCount(3);return factoryBean;}/*** 创建Trigger对象 Cron表达式* @return*/@Beanpublic CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();factoryBean.setJobDetail(jobDetailFactoryBean.getObject());// 设置触发的时间factoryBean.setCronExpression("0/3 * * * * ?");return factoryBean;}/*** 创建对应的Scheduler对象* @param cronTriggerFactoryBean* @return*/@Beanpublic SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean){SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();factoryBean.setTriggers(cronTriggerFactoryBean.getObject());return factoryBean;}
}
3. 启动器中放开
package com.gupaoedu;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling
public class GpSpringbootQuartzDemoApplication {public static void main(String[] args) {SpringApplication.run(GpSpringbootQuartzDemoApplication.class, args);}}
1.20 SpringBoot 整合 SpringDataJPA
1.20.1 添加依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- springBoot的启动器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><!-- druid连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.9</version></dependency>
</dependencies>
1.20.2 配置文件
# jdbc的相关配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/gp?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456# 配置连接池信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource# 配置JPA的相关参数
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
1.20.3 创建 POJO 对象
package com.gupaoedu.pojo;import javax.persistence.*;@Entity
@Table(name = "users")
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "id")private Integer id;@Column(name = "name")private String name;@Column(name = "age")private Integer age;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}
}
1.20.4 创建 Repository 接口
package com.gupaoedu.dao;import com.gupaoedu.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;public interface UserRepository extends JpaRepository<User,Integer> {
}
1.20.5 单元测试
package com.gupaoedu;import com.gupaoedu.dao.UserRepository;
import com.gupaoedu.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest
public class GpSpringbootJpaDemoApplicationTests {@Autowiredprivate UserRepository repository;@Testpublic void contextLoads() {User user = new User();user.setName("gupao");user.setAge(4);repository.save(user);}}
相关文章:
第十二章 微服务核心(一)
一、Spring Boot 1.1 SpringBoot 构建方式 1.1.1 通过官网自动生成 进入官网:https://spring.io/,点击 Projects --> Spring Framework; 拖动滚动条到中间位置,点击 Spring Initializr 或者直接通过 https://start.spring…...
MySQL索引18连问,谁能顶住
前言 过完这个节,就要进入金银季,准备了 18 道 MySQL 索引题,一定用得上。 作者:感谢每一个支持: github 1. 索引是什么 索引是一种数据结构,用来帮助提升查询和检索数据速度。可以理解为一本书的目录&…...
[flink 实时流基础系列]揭开flink的什么面纱基础一
Apache Flink 是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行,并能以内存速度和任意规模进行计算。 文章目录 0. 处理无界和有界数据无界流有界流 1. Flink程序和数据流图2. 为什么一定要…...
开放平台 - 互动玩法演进之路
本期作者 1. 背景 随着直播业务和用户规模日益壮大,如何丰富直播间内容、增强直播间内用户互动效果,提升营收数据变得更加关键。为此,直播互动玩法应运而生。通过弹幕、礼物、点赞、大航海等方式,用户可以参与主播的直播内容。B站…...
Linux之进程控制进程终止进程等待进程的程序替换替换函数实现简易shell
文章目录 一、进程创建1.1 fork的使用 二、进程终止2.1 终止是在做什么?2.2 终止的3种情况&&退出码的理解2.3 进程常见退出方法 三、进程等待3.1 为什么要进行进程等待?3.2 取子进程退出信息status3.3 宏WIFEXITED和WEXITSTATUS(获取…...
RegSeg 学习笔记(待完善)
论文阅读 解决的问题 引用别的论文的内容 可以用 controlf 寻找想要的内容 PPM 空间金字塔池化改进 SPP / SPPF / SimSPPF / ASPP / RFB / SPPCSPC / SPPFCSPC / SPPELAN  ASPP STDC:short-term dense concatenate module 和 DDRNet SE-ResNeXt …...
Qt中常用宏定义
Qt中常用宏定义 一、Q_DECLARE_PRIVATE(Class)二、Q_DECLARE_PRIVATE_D(Dptr, Class)三、Q_DECLARE_PUBLIC(Class)四、Q_D(Class) 和 Q_Q(Class) 一、Q_DECLARE_PRIVATE(Class) #define Q_DECLARE_PRIVATE(Class) inline Class##Private* d_func() { # 此处的 d_ptr 是属于QOb…...
【计算机网络】第 9 问:四种信道划分介质访问控制?
目录 正文什么是信道划分介质访问控制?什么是多路复用技术?四种信道划分介质访问控制1. 频分多路复用 FDM2. 时分多路复用 TDM3. 波分多路复用 WDM4. 码分多路复用 CDM 正文 什么是信道划分介质访问控制? 信道划分介质访问控制(…...
Rust编程(五)终章:查漏补缺
闭包 & 迭代器 闭包(Closure)通常是指词法闭包,是一个持有外部环境变量的函数。外部环境是指闭包定义时所在的词法作用域。外部环境变量,在函数式编程范式中也被称为自由变量,是指并不是在闭包内定义的变量。将自…...
LLM漫谈(五)| 从q star视角解密OpenAI 2027年实现AGI计划
最近,网上疯传OpenAI2027年关于AGI的计划。在本文,我们将针对部分细节以第一人称进行分享。 摘要:OpenAI于2022年8月开始训练一个125万亿参数的多模态模型。第一个阶段是Arrakis,也叫Q*,该模型于2023年12月完成训练&…...
【echart】数据可视化+vue+vite遇到问题
1、vue3使用echars图表报错:"Initialize failed:invalid dom" 原因是因为:Dom没有完成加载时,echarts.init() 就已经开始执行了,获取不到Dom,无法进行操作 解决:加个延时 onMounted(async () …...
mac m1安装和使用nvm的问题
mac m1安装和使用nvm的问题 使用nvm管理多版本node 每个项目可能用的node版本不同,所以需要多个版本node来回切换 但是最近遇到安装v14.19.0时一直安装失败的问题。 首先说明一下,用的电脑是mac M1芯片 Downloading and installing node v14.19.0... …...
git泄露
git泄露 CTFHub技能树-Web-信息泄露-备份文件下载 当前大量开发人员使用git进行版本控制,对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞。 工具GitHack使用:python2 GitHack.py URL地址/.git/ git命令…...
Java项目:78 springboot学生宿舍管理系统的设计与开发
作者主页:源码空间codegym 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统的角色:管理员、宿管、学生 管理员管理宿管员,管理学生,修改密码,维护个人信息。 宿管员…...
ArcGis Pro Python工具箱教程 03 工具箱中工具自定义
ArcGis Pro Python工具箱教程 03 工具箱中工具自定义 用于定义工作工具类的方法 工具方法必选或可选描述__ init __必需项right-aligned 初始化工具类。getParameterInfo可选定义工具的参数。isLicensed可选返回工具是否获得执行许可。updateParameters可选在用户每次在工具对…...
【C++初阶】之类和对象(中)
【C初阶】之类和对象(中) ✍ 类的六个默认成员函数✍ 构造函数🏄 为什么需要构造函数🏄 默认构造函数🏄 为什么编译器能自动调用默认构造函数🏄 自己写的构造函数🏄 构造函数的特性 ✍ 拷贝构造…...
Vue2(十一):脚手架配置代理、github案例、插槽
一、脚手架配置代理 1.回顾常用的ajax发送方式: (1)xhr 比较麻烦,不常用 (2)jQuery 核心是封装dom操作,所以也不常用 (3)axios 优势:体积小、是promis…...
在宝塔面板中,为自己的云服务器安装SSL证书,为所搭建的网站启用https(主要部分攻略)
前提条件 My HTTP website is running Nginx on Debian 10(或者11) 时间:2024-3-28 16:25:52 你的网站部署在Debain 10(或者11)的 Nginx上 安装单域名证书(默认)(非泛域名…...
学习JavaEE的日子 Day32 线程池
Day32 线程池 1.引入 一个线程完成一项任务所需时间为: 创建线程时间 - Time1线程中执行任务的时间 - Time2销毁线程时间 - Time3 2.为什么需要线程池(重要) 线程池技术正是关注如何缩短或调整Time1和Time3的时间,从而提高程序的性能。项目中可以把Time…...
@Transactional 注解使用的注意事项
事务管理 事务管理在系统开发中是不可缺少的一部分,Spring提供了很好的事务管理机制,主要分为编程式事务和声明式事务两种。 编程式事务: 是指在代码中手动的管理事务的提交、回滚等操作,代码侵入比较强。 声明式事务ÿ…...
电商系列之库存
> 插:AI时代,程序员或多或少要了解些人工智能,前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 坚持不懈,越努力越幸运,大家…...
Apache HBase(二)
目录 一、Apache HBase 1、HBase Shell操作 1.1、DDL创建修改表格 1、创建命名空间和表格 2、查看表格 3、修改表 4、删除表 1.2、DML写入读取数据 1、写入数据 2、读取数据 3、删除数据 2、大数据软件启动 一、Apache HBase 1、HBase Shell操作 先启动HBase。再…...
【设计模式】原型模式详解
概述 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象 结构 抽象原型类:规定了具体原型对象必须实现的clone()方法具体原型类:实现抽象原型类的clone()方法,它是可以被复制的对象。访问类&…...
企微侧边栏开发(内部应用内嵌H5)
一、背景 公司的业务需要用企业微信和客户进行沟通,而客户的个人信息基本都存储在内部CRM系统中,对于销售来说需要一边看企微,一边去内部CRM系统查询,比较麻烦,希望能在企微增加一个侧边栏展示客户的详细信息…...
如何确定最优的石油管道位置
如何确定最优的石油管道位置 一、前言二、问题概述三、理解问题的几何性质四、转化为数学问题五、寻找最优解六、算法设计6.1伪代码6.2 C代码七算法效率和实际应用7.1时间效率分析7.2 空间效率分析结论一、前言 当我们面对建设大型输油管道的复杂任务时,确保效率和成本效益是…...
FPGA 图像边缘检测(Canny算子)
1 顶层代码 timescale 1ns / 1ps //边缘检测二阶微分算子:canny算子module image_canny_edge_detect (input clk,input reset, //复位高电平有效input [10:0] img_width,input [ 9:0] img_height,input [ 7:0] low_threshold,input [ 7:0] high_threshold,input va…...
2024.3.28学习笔记
今日学习韩顺平java0200_韩顺平Java_对象机制练习_哔哩哔哩_bilibili 今日学习p286-p294 继承 继承可以解决代码复用,让我们的编程更加靠近人类思维,当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些…...
33.HarmonyOS App(JAVA)鸿蒙系统app数据库增删改查
33.HarmonyOS App(JAVA)鸿蒙系统app数据库增删改查 关系数据库 关系对象数据库(ORM) 应用偏好数据库 分布式数据库 关系型数据库(Relational Database,RDB)是一种基于关系模型来管理数据的数据库。HarmonyOS关系型…...
寄主机显示器被快递搞坏了怎么办?怎么破?
大家好,我是平泽裕也。 最近,我在社区里看到很多关于开学后弟弟寄来的电脑显示器被快递损坏的帖子。 看到它真的让我感到难过。 如果有人的数码产品被快递损坏了,我会伤心很久。 那么今天就跟大家聊聊寄快递的一些小技巧。 作为一名曾经的…...
python爬虫-bs4
python爬虫-bs4 目录 python爬虫-bs4说明安装导入 基础用法解析对象获取文本Tag对象获取HTML中的标签内容find参数获取标签属性获取所有标签获取标签名嵌套获取子节点和父节点 说明 BeautifulSoup 是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数…...
网站代理建设/长尾关键词排名工具
// 判断是否为手机号 isPoneAvailable: function (pone) { var myreg /^[1][3,4,5,7,8][0-9]{9}$/; if (!myreg.test(pone)) { return false; } else { return true; } }, // 判断是否为电话号码 isTelAvailable: function (tel) { var myreg /^(([0\]\d{2,3}-)?(0\d{2,3})-…...
做纺织生意用什么网站好/百度seo优化策略
AWStats安装使用说明(For Windows) 一、安装ActivePerl 因为AWStats是用Perl编写的程序,所以必须先安装ActivePerl(For Win32)程序。 这 里我选择的版本是ActivePerl-5.8.8.816-MSWin32-x86-255195.msi。如果选择.zip格式的安装包…...
深喉咙企业网站系统/广告推广怎么做最有效
java web项目里ehcache.xml介绍 作者: 字体:[增加 减小] 类型:转载java web项目里ehcache.xml介绍,需要的朋友可以参考一下id"cproIframe_u1892994_2" width"580" height"90" src"http://pos.…...
行政单位门户网站建设方案/全球搜索大全
1、阿里移动推荐算法: 答辩视频:https://space.dingtalk.com/c/gQHOEnXdXw 2、资金流入流出预测: 答辩视频:https://space.dingtalk.com/c/gQHOEnXi6w 3、阿里移动推荐&资金流入流出预测答辩PPT下载: https://ti…...
东莞网站建设定制/疫情最新数据消息
深入理解Class---常量池一、概念1、jvm生命周期启动:当启动一个java程序时,一个jvm实例就诞生了,任何一个拥有main方法的class都可以作为jvm实例运行的起点。运行:main()函数作为程序初始线程起点,其它线程由该线程启动…...
郑州小程序/厦门百度整站优化服务
国外的源访问很慢,可以用国内的源进行下载,这里以清华的源为例,命令如下: pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple 要安装的库的名称例如我要安装PyQt5,那么命令就是: pip3 install -…...