SpringBoot
Spring Boot静态资源映射规则
- 所有 /webjars/** 都去classpath:/META-INF/resource/webjars找资源
webjars:以jar宝的方式引入静态资源,在webjars官网搜索需要引入的资源和版本,直接将maven依赖加入对pom文件即可
在maven中加入依赖以后,会出现如下,游览器访问资源直接在这个文件夹下找对应的文件
- 自己的静态资源访问方式,在resource文件夹下
如下图
- 欢迎页 即首页,localhost:8080/寻找到是**/index
- 网站图标,在**/favicon.ioc
模板引擎thymeleaf用于支持jsp
- 引入thymeleaf:
<properties> <thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
2.把html(jsp)页面放到classpath:/templates/下thymeleaf即可开启访问跳转或者渲染支持,如下图即可跳转success页面
登录功能实现及拦截器
第一步,LoginController类实现登录成功的跳转,在确认密码是123456后构造一个session值key,value分别为<loginUser,username>用于拦截直接访问登录后才可以访问的main.html页面:
@Controller
public class LoginController {
@RequestMapping("/user/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model, HttpSession session){
if(!StringUtils.isEmpty(username)&&"123456".equals(password)){
session.setAttribute("loginUser",username);
return "redirect:/main.html";
}else{
model.addAttribute("msg","用户名或密码错误");
return "index";
}
}
}
第二步,配置拦截器**,SpirngBoot采用重写配置类接口的方式配置别忘了!!**不拦截登录页面和静态资源
package com.atguigu.kuang.config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.*;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/"
,"/user/login","/css/*","/img/*","/js/*");
}
}
第三步:继承HandlerInterceptor接口实现过滤操作
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//登录成功后应该有用户的session
Object loginUser = request.getSession().getAttribute("loginUser");
if(loginUser==null){
//没有登录
request.setAttribute("msg","没有权限,请先登录");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
return true;
}
}
}
嵌入式Servlet容器(待续)
SpringBoot默认是用的嵌入式Servlet容器(Tomcat),存在的问题是:
- 如何定制和修改Servlet容器相关配置
第一种方法:修改server有关ServerProperties的配置
第二种方法:编写一个EmbeddedServletContainerCustomizer类
Docker
Docker是一个开源的应用容器引擎,Docker支持将软件编译成镜像,其他使用者可以直接使用这个镜像。比如在某个服务器安装好Mysql,则在另外的服务器运行Mysql镜像就好,不需要再安装编译
docker使用步骤:
1)安装docker,并修改docker镜像源为国内
# 创建或修改 /etc/docker/daemon.json 文件,修改为如下形式
{
"registry-mirrors" : [
"https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn",
"http://hub-mirror.c.163.com",
"https://cr.console.aliyun.com/"
]
}
# 重启docker服务使配置生效
$ systemctl restart docker.service
开启docker
systemctl start docker
2)去docker仓库找到软件对应的镜像
搜索:docker search mysql
下载:docker pull mysql:5.5
显示本地所有镜像:docker images
删除镜像:docker rmi image-id
3)使用docker运行这个镜像,这个镜像会生成一个docker容器
生成容器:docker run --name mytomcat -d tomcat
查看运行中的容器:docker ps
停止容器:docker stop 容器id
删除容器:docker rm
4)对容器的启动停止就是对软件的启动停止
启动容器并作端口映射:docker run -d -p 8888:8080 tomcat
将虚拟机的8080端口映射到本地,这样外面也可以访问虚拟机tomcat
关闭防火墙:service firewalld stop
配置Mysql:
构造镜像:docker run -p 3306:3306 --name mysql101 -e MYSQL-ROOT_PASSWORD=123456 -d mysql --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
整合Mybatis
Mybatis主要功能是实现 游览器端——本地class——数据库 三者之间的映射
- 本地class:Department类,使用注解方式的时候无需构造函数和get、set方法
ackage com.atguigu.springboot.bean;
public class Department {
private Integer id;
private String departmentName;
public void setId(Integer id) {
this.id = id;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public Integer getId() {
return id;
}
public String getDepartmentName() {
return departmentName;
}
}
- DepartmentMapper接口:实现本地class和数据库之间的映射,使用@Mapper注解,等价于dao层,接口中的方法使用@Select、@Delete等注解
package com.atguigu.springboot.mapper;
import com.atguigu.springboot.bean.Department;
import org.apache.ibatis.annotations.*;
//指定这是一个操作数据库的mapper
//@Mapper
@Mapper
public interface DepartmentMapper {
@Select("select * from department where id=#{id}")
public Department getDeptById(Integer id);
@Delete("delete from department where id=#{id}")
public int deleteDeptById(Integer id);
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into department(departmentName) values(#{departmentName})")
public int insertDept(Department department);
@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department);
}
- DeptController类:游览器端的对数据库操作参数的输入到内置的DepartmentMapper类中。使用@Controller或@RestController注解等
@RestController=@ResponseBody + @Controller。内置方法使用@GetMapping、@PostMapping等注解用于处理get、post请求
@GetMapping("/get/{id}")等价于@RequestMapping(value = “/get/{id}”, method = RequestMethod.GET)
package com.atguigu.springboot.controller;
import com.atguigu.springboot.bean.Department;
import com.atguigu.springboot.mapper.DepartmentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DeptController{
@Autowired
DepartmentMapper departmentMapper;
@GetMapping("/dept/{id}")
public Department getDepartment(@PathVariable("id") Integer id){
return departmentMapper.getDeptById(id);
}
@GetMapping("/dept")
public Department insertDept(Department department){
departmentMapper.insertDept(department);
return department;
}
}
对于以上代码中:
1)在游览器输入http://localhost:8080/dept/1即可查询deparrtment1的内容并反馈到游览器
2)在游览器输入http://localhost:8080/dept?departmentName=AA可以直接设置departmentName为AA
3)如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。
例如:本来应该到success.jsp页面的,则其显示success.
4)如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行。
5)如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。
SpringBoot消息机制
消息机制用于提升系统异步通信能力、扩展解耦能力
异步处理:以用户注册为例,注册成功后将用户信息写入数据库,将需要的消息写进消息队列,然后立马返回通知用户,再通过异步读取的方式从消息队列中读取消息
应用解耦:将订单系统和库存系统分来来,将订单信息加入消息队列,然后库存系统订阅消息队列,如果一旦有订单就收到消息队列的信息
**流量削峰:**如果用户有10w的请求直接发送给tomcat的秒杀业务处理,则肯定会卡死,这时候需要在用户请求和秒杀业务处理之间设置一个消息队列,并给消息队列设置一个1w的最大值,则秒杀业务处理系统可以直接在消息队列中读取用户请求
消息代理:消息中间件服务器就是一种代理
目的地:指的是消息中间件服务器将消息发送给谁
消息队列主要有两种形式的目的地:
1.队列:点对点消息通信,消息只有唯一的发送者和接受者,但是可以有很多接收者。比如A发送消息到消息队列,BCD都可以从中读取,但是BCD中只有一个可以读取到,且某个读取到之后该消息就删除了
2.主题:发布/订阅消息通信,发布者发送消息到主题,多个订阅者监听这个主题,那么订阅者可以同时收到消息
JMS:java消息服务,ActiveMQ是JMS的实现
AMQP:高级消息队列协议,RabbitMQ是AMQP的实现
RabbitMQ
Message:消息,消息是不具名的,它由消息头和消息体组成,消息头包括路由键,优先级,持久性等
Publisher:消息的生产者
Exchange:交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列
Queue:消息队列,用来保存消息知道发送给消费者,它是消息的容器,也是消息的终点
Binding:用于交换器和消息队列之间的绑定,一个交换器可以绑定多个消息队列
Connect:网络连接
Channel:信道,用于解决多路复用,消息的发送和接受复用一条tcp连接,在一条tcp连接中开多个信道
Consumer:消息的消费者
Virtual Host:每个host本质上就是一个mini版的RabbitMQ服务器,拥有自己的独立的队列、交换器、绑定和权限机制
Broker:表示消息队列服务器实体
Exchange类型:
1)direct:消息中的路由键如果和Binding中的binding key完全一致,则交换器就将消息发送到对应的队列中,完全是匹配、单播模式
2)fanout :路由器对绑定的所有队列都发送一份消息
3)topic:通过对binding key的模糊匹配来决定发送到哪个消息队列
RabbitMQ演示
第一步:开启rabbitmq镜像
docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq 68898be27496
第二步:访问http://192.168.110.128:15672/,用户名密码都是guest,进入RabbitMQ管理界面
第三步:
创建新的交换机,一共创建exchange.direct和exchange.fanout两个交换机
第四部:创建新的队列
第五步:绑定消息队列和交换器
1)绑定exchange.direct和四个消息队列
2)绑定exchange.fanout和四个消息队列
3)绑定exchange.topic, #表示多个字符,*表示一个字符
第六步,测试
1)使用exchange.direct发送消息,只有atguigu队列可以收到,因为Routing key为atguigu
2)使用exchange.topic发送,会根据Routing key进行匹配而决定发送到哪个消息队列中
RabbitMQ代码操作
第一步:配置properties文件配置主机号和账号密码
第二步:使用RabbitTemplate类给RabbitMQ发送和接受消息
rabbitTemplate.convertAndSend()可以实现自动序列化
第三步:如果需要将数据序列化为json,则可以自己实现一个MessageConverter类,其中使用jackson2实现对json的转换
第四步:实现对消息队列的监听,比如库存系统监听订单系统发送的消息队列
在springapplication类中加入@EnableRabbit注解开启基于注解的rabbitmq模式
新定义service.BookService类并使用@RabbotListene注解实现对消息队列的监听
第五步:AmqpAdmin类,RabbitMQ系统管理功能组件,用于创建和删除交换器和消息队列
分布式
把用户模块独立部署到多个模块,把订单模块独立部署到多个模块,如果用户模块想要使用订单模块的数据,就需要使用RPC(远程过程调用),RPC一般使用dubbo或者springcloud分布式服务框架。当用户模块选择哪台机器上的订单模块时,需要通过注册中心来询问,注册中心一般使用ZooKeeper
zookeeper运行 :
docker run --name zk01 -p 2181:2181 --restart always -d 36b7f3aa2340
dubbo的使用:
创建服务者
服务者:
1.将服务提供者注册到注册中心
1)在provider.pom文件中引入bubbo和zookeper依赖
2)配置dubbo扫描包和注册中心地址
3) 在TicketServiceImpl中使用@Service来发布服务
2.消费者使用服务
1)引入依赖,和服务提供者引入相同的bubbo和zookeper依赖
2)配置dubbo的注册中心地址
3)引用服务
在consumer工程下复制一份ticket-provider的相同路径(相同全类名)
在userservice中使用@Reference注解来远程引用ticketService的方法