目录
1、基本介绍
▶ 基本概念
SpringMVC是一种基于Java实现MVC模型的轻量级Web框架
▷ 优点
● 使用简单、开发便捷(相比于Servlet)
● 灵活性强
▷ 当前WEB程序的工作流程:
● 三层架构
○ web程序通过浏览器访问前端页面,发送异步请求到后端服务器
○ 后台服务器采用三层架构进行功能开发
○表现层负责接收请求和数据然后将数据转交给业务层
○ 业务层负责调用数据层完成数据库表的增删改查,并将结果返给表现层
○ 表现层将数据转换成json格式返回给前端○前端页面将数据进行解析最终展示给用户。
▷ 表现层与数据层的技术选型:
● 数据层采用Mybatis框架
● 变现层采用SpringMVC框架,SpringMVC主要负责的内容有:
○controller如何接收请求和数据
○ 如何将请求和数据转发给业务层
○ 如何将响应数据转换成json发回到前端
▶ 程序流程
1.浏览器发送请求到Tomcat服务器
2.Tomcat服务器接收到请求后,会将请求交给SpringMVC中的DispatcherServlet[前端控制器]来处理请求
3.DispatcherServlet不真正处理请求,只是按照对应的规则将请求分发到对应的Bean对象
4.Bean对象是有我们自己编写来处理不同的请求,每个Bean中可以处理一个或多个不同的请求url
5.DispatcherServlet和Bean对象都需要交给Spring容器来进行管理
▶ 知识点
@Controller
@RequestMapping
@ResponseBody
▶ 入门案例
● AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类
● AbstractDispatcherServletInitializer提供三个接口方法供用户实现
○ createServletApplicationContext()方法,创建Servlet容器时,加载SpringMVC对应bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围
protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; }○ createRootApplicationContext()方法,如果创建Servlet容器时需要加载非SpringMVC对的bean,使用当前方法进行,使用方式同createServletApplicationContext()
protected WebApplicationContext createRootApplicationContext() { return null; }○ getServletMappings()方法,设定SpringMVC对应的请求映射路径,设置为/表示拦截所请求,任意请求都将转入到SpringMVC进行处理
protected String[] getServletMappings() { return new String[]{"/"}; }2、工作流程
▶ 启动服务器初始化过程
1. 服务器启动,执行ServletContainersInitConfig类,初始化web容器
2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象
● 该方法加载SpringMVC的配置类SpringMvcConfig来初始化SpringMVC的容器
3. 加载SpringMvcConfig配置类
4. 执行@ComponentScan加载对应的bean
● 扫描指定包下所有类上的注解,如Controller类上的@Controller注解
5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法
● 此时就建立了 `/save` 和 save方法的对应关系
6. 执行getServletMappings方法,定义所有的请求都通过SpringMVC
● `/`代表所拦截请求的路径规则,只有被拦截后才能交给SpringMVC来处理请求
▶ 单次请求过程
1. 发送请求localhost/save
2. web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理
● 因为符合上面第六步设置的请求路径,所以该请求会交给SpringMVC来处理
3. 解析请求路径/save
4. 由/save匹配执行对应的方法save()
● 上面的第五步已经将请求路径和方法建立了对应关系,通过/save就能找到对应的save方法
5. 执行save()
6. 检测到有@ResponseBody直接将save()方法的返回值作为响应求体返回给请求方
3、bean加载控制
▶ Controller加载控制与业务bean加载控制
● SpringMVC相关bean(表现层bean)
● Spring控制的bean
○ 业务bean(Service)
○ 功能bean(DataSource等)
●SpringMVC相关bean加载控制
○ SpringMVC加载的bean对应的包均在com.itheima.controller包内
● Spring相关bean加载控制
○ 方式一:Spring加载的bean设定扫描范围为com.itheima,排除掉controller包内的bean
○ 方式二:Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
○ 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中
▶ 知识点
▶ bean的加载格式
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } protected WebApplicationContext createRootApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringConfig.class); return ctx; } protected String[] getServletMappings() { return new String[]{"/"}; } }▶ 简化开发
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{ protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } }
1、请求映射路径
2、请求方式
▶ Get请求
● 普通参数:url地址传参,地址参数名与形参变量名相同,定义形参即可接收参数
@RequestMapping("/commonParam") @ResponseBody public String commonParam(String name ,int age){ System.out.println("普通参数传递 name ==> "+name); System.out.println("普通参数传递 age ==> "+age); return "{'module':'common param'}"; }▶ post请求
● 普通参数:form表单post请求传参,表单参数名与形参变量名相同,定义形参即可接收参数
@RequestMapping("/commonParam") @ResponseBody public String commonParam(String name ,int age){ System.out.println("普通参数传递 name ==> "+name); System.out.println("普通参数传递 age ==> "+age); return "{'module':'common param'}"; }▶ Post请求中文乱码处理
● 为web容器添加过滤器并指定字符集,Spring-web包中提供了专用的字符过滤器
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{ // 配字符编码过滤器 protected Filter[] getServletFilters() { CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("utf-8"); return new Filter[]{filter}; } }3、请求参数
▶ 普通参数:url地址传参,地址参数名与形参变量名相同,定义形参即可接收参数
@RequestMapping("/commonParam") @ResponseBody public String commonParam(String name ,int age){ System.out.println("普通参数传递 name ==> "+name); System.out.println("普通参数传递 age ==> "+age); return "{'module':'common param'}"; }▶ 普通参数:请求参数名与形参变量名不同,使用@RequestParam绑定参数关系
@RequestMapping("/commonParamDifferentName") @ResponseBody public String commonParamDifferentName(@RequestParam("name")String userName , int age){ System.out.println("普通参数传递 userName ==> "+userName); System.out.println("普通参数传递 age ==> "+age); return "{'module':'common param different name'}"; }▶ @RequestParam
▶ POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数
@RequestMapping("/pojoParam") @ResponseBody public String pojoParam(User user){ System.out.println("pojo参数传递 user ==> "+user); return "{'module':'pojo param'}"; }▶ 嵌套POJO参数:POJO对象中包含POJO对象
▶ 嵌套POJO参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数
@RequestMapping("/pojoContainPojoParam") @ResponseBody public String pojoContainPojoParam(User user){ System.out.println("pojo嵌套pojo参数传递 user ==> "+user); return "{'module':'pojo contain pojo param'}"; }▶ 数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数
@RequestMapping("/arrayParam") @ResponseBody public String arrayParam(String[] likes){ System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes)); return "{'module':'array param'}"; }▶ 集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系
@RequestMapping("/listParam") @ResponseBody public String listParam(@RequestParam List<String> likes){ System.out.println("集合参数传递 likes ==> "+ likes); return "{'module':'list param'}"; }4、请求参数(传递json数据)
▶ 接收请求中的json数据
▷ ①:添加json数据转换相关坐标
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>▷ ②:设置发送json数据(请求body中添加json数据)
▷ ③:开启自动转换json数据的支持
@Configuration @ComponentScan("com.itheima.controller") @EnableWebMvc public class SpringMvcConfig { }注意事项:@EnableWebMvc注解功能强大,该注解整合了多个功能,此处仅使用其中一部分功能,即json数据进行自动类型转换。
▷ ④:设置接收json数据
@RequestMapping("/listParamForJson") @ResponseBody public String listParamForJson(@RequestBody List<String> likes){ System.out.println("list common(json)参数传递 list ==> "+likes); return "{'module':'list common for json param'}"; }▶ @EnableWebMvc
▶ @RequestBody
▶ POJO参数:json数据与形参对象属性名相同,定义POJO类型形参即可接收参数
@RequestMapping("/pojoParamForJson") @ResponseBody public String pojoParamForJson(@RequestBody User user){ System.out.println("pojo(json)参数传递 user ==> "+user); return "{'module':'pojo for json param'}"; }▶ POJO集合参数:json数组数据与集合泛型属性名相同,定义List类型形参即可接收参数
@RequestMapping("/listPojoParamForJson") @ResponseBody public String listPojoParamForJson(@RequestBody List<User> list){ System.out.println("list pojo(json)参数传递 list ==> "+list); return "{'module':'list pojo for json param'}"; }▶ @RequestBody与@RequestParam区别
● 区别
○ @RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】
○ @RequestBody用于接收json数据【application/json】
● 应用
○ 后期开发中,发送json格式数据为主,@RequestBody应用较广
○ 如果发送非json格式数据,选用@RequestParam接收请求参数
5、日期类型参数传递
▶ 参数传递
● 日期类型数据基于系统不同格式也不尽相同
○ 2088-08-18
○ 2088/08/18
○ 08/18/2088
● 接收形参时,根据不同的日期格式设置不同的接收方式
@RequestMapping("/dataParam") @ResponseBody public String dataParam(Date date, @DateTimeFormat(pattern = "yyyy-MM-dd") Date date1, @DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss")Date date2){ System.out.println("参数传递 date ==> "+date); System.out.println("参数传递 date(yyyy-MM-dd) ==> "+date1); System.out.println("参数传递 date(yyyy/MM/dd HH:mm:ss) ==> "+date2); return "{'module':'data param'}"; }http://localhost/dataParam?date=2088/08/08&date1=2088-08-18&date2=2088/08/28 8:08:08▶ @DateTimeFormat
▶ 类型转换器
● Converter接口
public interface Converter<S, T> { @Nullable T convert(S var1); }○ 请求参数年龄数据(String→Integer)
○ json数据转对象(json → POJO)
○ 日期格式转换(String → Date)
● @EnableWebMvc功能之一:根据类型匹配对应的类型转换器
▶ 响应页面(了解)
@RequestMapping("/toPage") public String toPage(){ return "page.jsp"; }▶ 响应文本数据(了解)
@RequestMapping("/toText") @ResponseBody public String toText(){ return "response text"; }▶ 响应json数据(对象转json)
@RequestMapping("/toJsonPOJO") @ResponseBody public User toJsonPOJO(){ User user = new User(); user.setName("赵云"); user.setAge(41); return user; }▶ 响应json数据(对象集合转json数组)
@RequestMapping("/toJsonList") @ResponseBody public List<User> toJsonList(){ User user1 = new User(); user1.setName("赵云"); user1.setAge(41); User user2 = new User(); user2.setName("master 赵云"); user2.setAge(40); List<User> userList = new ArrayList<User>(); userList.add(user1); userList.add(user2); return userList; }▶ @ResponseBody
▶ HttpMessageConverter接口
public interface HttpMessageConverter<T> { boolean canRead(Class<?> clazz, @Nullable MediaType mediaType); boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType); List<MediaType> getSupportedMediaTypes(); T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException; }
1、REST简介
▶ 基本介绍
REST(Representational State Transfer),表现形式状态转换
● 传统风格资源描述形式
○ http://localhost/user/getById?id=1
○ http://localhost/user/saveUser
● REST风格描述形式
○ http://localhost/user/1
○ http://localhost/user
● 优点:
○ 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
○ 书写简化
▶ 风格简介
上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范 描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如:users、books、accounts……
2、RESTful入门案例
▶ ①:设定http请求动作(动词)
@RequestMapping(value = "/users", method = RequestMethod.POST) @ResponseBody public String save(@RequestBody User user){ System.out.println("user save..." + user); return "{'module':'user save'}"; } @RequestMapping(value = "/users" ,method = RequestMethod.PUT) @ResponseBody public String update(@RequestBody User user){ System.out.println("user update..."+user); return "{'module':'user update'}"; }▶ ②:设定请求参数(路径变量)
@RequestMapping(value = "/users/{id}" ,method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable Integer id){ System.out.println("user delete..." + id); return "{'module':'user delete'}"; }▶ @RequestMapping
▶ @PathVariable
▶ @RequestBody,@RequestParam,@PathVariable 三者区别
● 区别
○ @RequestParam用于接收url地址传参或表单传参
○ @RequestBody用于接收json数据
○ @PathVariable用于接收路径参数,使用{参数名称}描述路径参数
● 应用
○ 后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广
○ 如果发送非json格式数据,选用@RequestParam接收请求参数
○ 采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求径变量,通常用于传递id值
3、RESTful快速开发
▶ 快速开发
▶ @RestController
▶ @GetMapping @PostMapping @PutMapping @DeleteMapping
▶ 基于RESTful页面数据交互
①:制作SpringMVC控制器,并通过PostMan测试接口功能
②:设置对静态资源的访问放行
③:前端页面通过异步提交访问后台控制器
1、拦截器概念
▶ 基本介绍
(1)浏览器发送一个请求会先到Tomcat的web服务器
(2)Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源
(3)如果是静态资源,会直接到Tomcat的项目部署目录下去直接访问
(4)如果是动态资源,就需要交给项目的后台代码进行处理
(5)在找到具体的方法之前,我们可以去配置过滤器(可以配置多个),按照顺序进行执行
(6)然后进入到到中央处理器(SpringMVC中的内容),SpringMVC会根据配置的规则进行拦截
(7)如果满足规则,则进行处理,找到其对应的controller类中的方法进行执行,完成后返回结果
(8)如果不满足规则,则不进行处理
(9)这个时候,如果我们需要在每个Controller方法执行的前后添加业务,具体该如何来实现?
这个就是拦截器要做的事。
▷ 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
● 作用:
○ 在指定的方法调用前后执行预先设定的代码
○ 阻止原始方法的执行
○ 总结:拦截器就是用来做增强
▶ 拦截器和过滤器之间的区别是什么?
● 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
● 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
2、拦截器开发
▶ 步骤1 : 创建拦截器类
让类实现HandlerInterceptor接口,重写接口中的三个方法。
@Component //定义拦截器类,实现HandlerInterceptor接口 //注意当前类必须受Spring容器控制 public class ProjectInterceptor implements HandlerInterceptor { @Override //原始方法调用前执行的内容 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle..."); return true; } @Override //原始方法调用后执行的内容 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle..."); } @Override //原始方法调用完成后执行的内容 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion..."); } }注意: 拦截器类要被SpringMVC容器扫描到。
▶步骤2 : 配置拦截器类
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor projectInterceptor; @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); } @Override protected void addInterceptors(InterceptorRegistry registry) { //配置拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books" ); } }▶步骤3 : SpringMVC添加SpringMvcSupport包扫描
@Configuration @ComponentScan({"com.itheima.controller","com.itheima.config"}) @EnableWebMvc public class SpringMvcConfig{ }▶ 步骤4 : 运行程序测试
使用PostMan发送`http://localhost/books`
如果发送`http://localhost/books/100`会发现拦截器没有被执行,原因是拦截器的`addPathPatterns`方法配置的拦截路径是`/books`,我们现在发送的是`/books/100`,所以没有匹配上,因此没有拦截,拦截器就不会执行。
▶ 步骤5 : 修改拦截器拦截规则
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor projectInterceptor; @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); } @Override protected void addInterceptors(InterceptorRegistry registry) { //配置拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*" ); } }这个时候,如果再次访问`http://localhost/books/100`,拦截器就会被执行。拦截器中的`preHandler`方法,如果返回true,则代表放行,会执行原始Controller类中要请求的方法,如果返回false,则代表拦截,后面的就不会再执行了。
▶ 步骤6 : 简化SpringMvcSupport的编写
@Configuration @ComponentScan({"com.itheima.controller"}) @EnableWebMvc //实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性 public class SpringMvcConfig implements WebMvcConfigurer { @Autowired private ProjectInterceptor projectInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { //配置多拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*"); } }▶ 拦截器的执行流程
当有拦截器后,请求会先进入preHandle方法,
如果方法返回true,则放行继续执行后面的handle[controller的方法]和后面的方法
如果返回false,则直接跳过后面方法的执行。
3、拦截器参数▶ 前置处理方法
原始方法之前运行preHandle
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); return true; }● request:请求对象
● response:响应对象
● handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装
使用request对象可以获取请求数据中的内容,如获取请求头的`Content-Type`
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String contentType = request.getHeader("Content-Type"); System.out.println("preHandle..."+contentType); return true; }使用handler参数,可以获取方法的相关信息
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HandlerMethod hm = (HandlerMethod)handler; String methodName = hm.getMethod().getName();//可以获取方法的名称 System.out.println("preHandle..."+methodName); return true; }▶ 后置处理方法
原始方法运行后运行,如果原始方法被拦截,则不执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); }前三个参数和上面的是一致的。
modelAndView : 如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整。因为现在都是返回json数据,所以该参数的使用率不高。
▶ 完成处理方法
拦截器最后执行的方法,无论原始方法是否执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); }前三个参数与上面的是一致的。
ex : 如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理,因为我们现在已经有全局异常处理器类,所以该参数的使用率也不高。
这三个方法中,最常用的是preHandle,在这个方法中可以通过返回值来决定是否要进行放行,我们可以把业务逻辑放在该方法中,如果满足业务则返回true放行,不满足则返回false拦截。
4、拦截器链配置
▶ 配置多个拦截器
▷ 步骤1 : 创建拦截器类
实现接口,并重写接口中的方法
@Component public class ProjectInterceptor2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle...222"); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle...222"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion...222"); } }▷ 步骤2 : 配置拦截器类
@Configuration @ComponentScan({"com.itheima.controller"}) @EnableWebMvc //实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性 public class SpringMvcConfig implements WebMvcConfigurer { @Autowired private ProjectInterceptor projectInterceptor; @Autowired private ProjectInterceptor2 projectInterceptor2; @Override public void addInterceptors(InterceptorRegistry registry) { //配置多拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*"); registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*"); } }▷ 步骤3 : 运行程序,观察顺序
拦截器执行的顺序是和配置顺序有关。先进后出。
● 当配置多个拦截器时,形成拦截器链
● 拦截器链的运行顺序参照拦截器添加顺序为准
● 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
● 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作
● preHandle :与配置顺序相同,必定运行
● postHandle : 与配置顺序相反,可能不运行
● afterCompletion : 与配置顺序相反,可能不运行。
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
目录H2数据库入门以及实际开发时的使用1.H2数据库的初识1.1H2数据库介绍1.2为什么要使用嵌入式数据库?1.3嵌入式数据库对比1.3.1性能对比1.4技术选型思考2.H2数据库实战2.1H2数据库下载搭建以及部署2.1.1H2数据库的下载2.1.2数据库启动2.1.2.1windows系统可以在bin目录下执行h2.bat2.1.2.2同理可以通过cmd直接使用命令进行启动:2.1.2.3启动后控制台页面:2.1.3spring整合H2数据库2.1.3.1引入依赖文件2.1.4数据库通过file模式实际保存数据的位置2.2H2数据库操作2.2.1Mysql兼容模式2.2.2Mysql模式
为什么需要服务网关传统的单体架构中只需要开放一个服务给客户端调用,但是微服务架构中是将一个系统拆分成多个微服务,如果没有网关,客户端只能在本地记录每个微服务的调用地址,当需要调用的微服务数量很多时,它需要了解每个服务的接口,这个工作量很大。有了网关之后,网关作为系统的唯一流量入口,封装内部系统的架构,所有请求都先经过网关,由网关将请求路由到合适的微服务。使用网关的好处1)简化客户端的工作。网关将微服务封装起来后,客户端只需同网关交互,而不必调用各个不同服务;(2)降低函数间的耦合度。一旦服务接口修改,只需修改网关的路由策略,不必修改每个调用该函数的客户端,从而减少了程序间的耦合性(3)解放开发
我发现python的细节自动完成很好RubyonRails有类似的方法描述吗? 最佳答案 有篇不错的文章"UsingVIMasacompleteRubyonRailsIDE"其中引用rails.vim.这似乎是RailsforVIM的实际标准。(不过,我还没有使用过它,但很快就会尝试。)这允许你做很多与Rails相关的任务,但对自动完成没有帮助。还有一篇"RubyAutocompleteinVim"(遗憾的是不再可用)这就是您要搜索的内容。我不知道,理解Rails的所有插件魔法和元编程的东西是否足够聪明。它至少在vim的配置中提到了
防火墙防火墙分类第一代防火墙:包过滤防火墙包过滤防火墙的缺点第二代防火墙:代理防火墙第三代防火墙:状态防火墙第四代防火墙:UTM防火墙第五代防火墙:下一代防火墙华为防火墙介绍安全策略防火墙的会话表防火墙分类第一代防火墙:包过滤防火墙属于第一代防火墙技术,在没有专用防火墙设备时,一般由路由器实现该功能。将网络上传送数据包的IP首部以及TCP/UDP首部,获取发送源的IP地址和端口号,以及目的地的IP地址和端口号,并将这些信息作为过滤条件,决定是否将该分组转发至目的地网络分组过滤的执行需要设置访问控制列表。访问控制列表也可以称为安全策略(简称策略)或安全规则(简称规则)。类似于进站检票的做法,符合
内容来自Qt样式表之QSS语法介绍-3YL的博客Qt样式表是一个可以自定义部件外观的十分强大的机制,可以用来美化部件。Qt样式表的概念、术语和语法都受到了HTML的层叠样式表(CascadingStyleSheets, CSS教程)的启发,不过与CSS不同的是,Qt样式表应用于部件的世界。类型选择器QPushButton匹配QPushButton及其子类的实例ID选择器QPushButton#okButton匹配所有objectName为okButton的QPushButton实例。 CSS常用样式1CSS文字属性注:px:相对长度单位,像素(Pixel)。pt:绝对长度单位,点(Point
简介:我们都知道在Android开发中,当我们的程序在与用户交互时,用户会得到一定的反馈,其中以对话框的形式的反馈还是比较常见的,接下来我们来介绍几种常见的对话框的基本使用。前置准备:(文章最后附有所有代码)我们首先先写一个简单的页面用于测试这几种Dialog(对话框)代码如下,比较简单,就不做解释了一、提示对话框(即最普通的对话框)首先我们给普通对话框的按钮设置一个点击事件,然后通过AlertDialog.Builder来构造一个对象,为什么不直接Dialog一个对象,是因为Dialog是一个基类,我们尽量要使用它的子类来进行实例化对象,在实例化对象的时候,需要将当前的上下文传过去,因为我这
作者:郭斌斌爱可生DBA团队成员,负责项目日常问题处理及公司平台问题排查。本文来源:原创投稿*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。OceanBase集群界面会展示Observer的资源水位,今天简单了解一下资源水位的数值代表的含义以及关联参数现有test_1集群,只有一个sys租户Sys租户的资源配置:Cpu:2.5-5Memory:3G-3GUnit:1集群的资源水位信息以10.186.63.198为例,浅看一下cpu、内存、磁盘的含义以及相关联参数cpu:2.5/17核2.5代表observer上已经分配给租户的cpu核数,该数值是租户的MinCPU
快捷目录前言一、涉及到的相关技术简介二、具体实现过程及踩坑杂谈1.安卓手机改造成linux系统实现方案2.改造后的手机Linux中软件的安装3.手机Linux中安装MySQL5.7踩坑实录4.手机Linux中安装软件的正确方法三、Linux服务器部署前后端分离项目流程1.前提准备(安装必要软件,搭建环境):2.前后端分离项目的详细部署过程:总结前言总体概述:本篇文章隶属于“手机改造服务器部署前后端分离项目”系列专栏,该专栏将分多个板块,每个板块独立成篇来详细记录:手机(安卓)改造成个人服务器(Linux)、Linux中安装软件、配置开发环境、部署JAVA+VUE+MySQL5.7前后端分离项目
涡旋光束及其MATLAB实现前言涡旋光束的基本概念常见的涡旋涡旋光束涡旋光束的产生方法前言笔者新开一块专栏,专门用于讨论整理总结涡旋光束的相关内容,从基本的概念出发,推导相关的公式,并结合MATLAB进行相关的仿真,不清楚这个专栏会更新多少期,我会分享部分的代码,全部的代码有需要的话可以私聊我。当然大家对这个专栏感兴趣的话,欢迎积极交流。涡旋光束的基本概念涡旋光束(vortexbeam)是指携带光学涡旋,具有exp(imϕ)exp(im\phi)exp(imϕ)相位分布的光束,其中mmm表示相位拓扑电荷数,ϕ\phiϕ是柱坐标下的方位角。之前的分享中笔者已经说明了部分的激光光束的表达式,想要