项目优化考虑方向
1 框架优化,若追求性能,尽量不要使用框架,用最底层代码编写项目 如:不使用mybatis而直接使用jdbc连接数据库操作,不使用SpringCloud而使用Dubbo框架(因为dubbo框架数据传输是序列化数据,更加快速,而SpringCloud传输数据是基于http协议远程调用)
2 sql语句优化 如:尽量不使用复杂sql,使用多条短sql,添加优化索引,使用union all不要使用union(去重影响性能能),不要使用select * 等
3 代码业务逻辑优化 如: 使用降级代码在controller层就降级比在service层降级性能稍好一点. 分页时起始位置一定不能在数据库计算,应该在业务层计算出值后直接传入数据库使用才行. 可以使用AOP面向切面编程启用异步方法执行(启动类上@EnableAsync 可以异步执行的方法(如保存日志信息等)的方法上添加@Async注解该方法启动异步线程执行 这样能很好的提高性能–使用时可以在yml文件中做一下线程配置或使用默认的也行…) 在前端页面中就使用ajax局部刷新异步请求提高性能
4 使用缓存redisCluster集群,将查询数据存入缓存中,读取时直接在缓存中读取,不需要查询数据库,性能会提高很多. 其实AOP中底层也有cache缓存(启动类上添加注解@EnableCaching 在需要缓存的方法上添加@Cacheable(value = “deptCache”)指定value值底层实际是一个map集合)满足不了需求的话就使用第三方的缓存!!!
Spring Boot
Spring Boot构建于Spring框架基础之上,基于快速构建理念,提供了自动配置功能,可实现其开箱即用特性其核心主要有如下几个方面:
起步依赖(Starter Dependency)。
自动配置(Auto Configuration)。
健康检查(Actator)-监控。
Spring Boot 的核心注解
启动类上面的注解是 ** @SpringBootApplication ** ,它也是 Spring Boot 的核心注解,主要组合包含了 3 个注解:
@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring组件扫描。
Spring Boot 自动配置原理是什么?
注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,
@EnableAutoConfiguration 给容器导入META-INF/spring.factories 里定义的自动配置类。
筛选有效的自动配置类。
每一个自动配置类结合对应的 xxxProperties.java 读取配置文件进行自动配置功能
Spring Boot中常用注解汇总
@SpringBootApplication
@Controller @Service @Component @Mapper
@RequestMapping("/")
@ResponseBody
@RestController
@PathVariable
@Scope(“singleton”)
@Lazy
@SpringBootTest
@Autowired @Qualifier(“defaultCache”)
@PostConstruct :描述bean对象生命周期方法中的初始化方法,此方法会在对象的构造方法之后执行。
@preDestroy :描述Bean对象生命周期方法中的销毁方法,此方法会在对象销毁之前执行(当作用域为prototype时,此方法不会执行)。
@Test
Mapper接口中
@Mapper
@Select(" sql语句 “) @insert(” sql语句 “) @update(” sql语句 “) @delete(” sql语句 ")
@Param(“ids”) //–int deleteObjects(@Param(“ids”)Integer… ids);
Pojo类中
Lombok注解
@DataTimeFormat(pattern=“yyyy/MM/dd HH:mm:ss”)
mybatis-plus中
@TableName(“tb_item_cat”)
@TableId(type = IdType.AUTO)
Lombok插件
@Data @Setter @Getter @ToString @EqualsAndHashCode
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Slf4J
项目中需要的基本依赖
1 需要连接数据库操作的(mybatis)
mysql依赖(数据库驱动依赖)
jdbc依赖
mybatis启动依赖(注意必须加上版本号!)
2 整合SpringMVC需要的依赖
web依赖(提供了springmvc的核心API及嵌套一个Tomcat服务器)
Thymeleaf依赖(html模板引擎提供了一个视图解析器对象及数据绑定机制)
Thymeleaf模板引擎常用标签有哪些?(th:each,th:text,th:value,th:href,…)
3 健康检查依赖
actuator依赖
http://localhost/actuator
4 热部署devtools依赖
5 Lombok插件依赖(@Data)
需要单独安装插件到STS或Idea中
项目中properties或yml配置文件的基本配置
//添加视图解析器配置(假默认配置prefix默认值为classpath:/templates/,后缀默认为.html)。
spring.thymeleaf.prefix=classpath:/templates/pages/
spring.thymeleaf.suffix=.html
//mybatis简易配置--超时时间及开启驼峰命名匹配
mybatis.configuration.default-statement-timeout=30
mybatis.configuration.map-underscore-to-camel-case=true
//配置mybatis中的sql日志的输出:(com.cy为我们写的项目的根包)
logging.level.com.cy=DEBUG
//希望查看更多actuator选项时配置
management.endpoints.web.exposure.include=*
SSO单点登录
当用户登陆时,通过nginx访问jt-web中任意的服务器之后输入用户名和密码访问JT-SSO单点登录服务器.
获取用户的登陆信息查询数据库,校验用户名和密码是否正确.如果用户名和密码是正确的,将用户信息转化为JSON串.之后生成加密的秘钥TOKEN(MD5(盐值+随机数)).将token:userJSON保存redis中.并且将token信息返回给客户端(jt-web).
Jt-web接收到服务端数据时首先校验数据是否有效.如果数据准确无误,将token信息写入到浏览器的Cookie(4K)中
当用户再次访问jt-web时,首先应该获取用户的Token信息,之后查询redis缓存服务器获取userJSON数据,之后将userJSON转化为User对象进行使用.实现免密登录.如果token数据为null,那么则让用户访问登陆页面.
SSO中将用户转化为Json 及 Json转化为对象
通过fasterxml组织提供的ObjectMapper(对象映射)这个对象的API writeValueAsString()和readValue()
private static final ObjectMapper MAPPER = new ObjectMapper(); //创建ObjectMapper对象
String jsonS = MAPPER.writeValueAsString(obj); //利用ObjectMapper对象的API , writeValueAsString()将对象转化为Json
//将Json转化为对象
MAPPER.readValue(json, target); //target是目标对象类型
//!!!!!!注意在js接收到json对象时需要转化为实体对象(可能是一个,也可能是对象List集合,所以要遍历取出)
var obj=JSON.parse(result); //JSON为js中的一个内置对象
UUID用法及密码加密工具类(DigestUtils) --Spring框架提供
UUID.randomUUID(); //获取UUID
UUID.randomUUID().toString(); //UUID转化为String字符串
//密码加密
//通过DigestUtils这个工具类对象的API md5DigestAsHex(password.getBytes()); //将密码转化为byte数组后通过该API将数组转化为16进制的加密字符串!!
String password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
UUID用法及密码加密工具类(SimpleHash) --Shiro框架提供
String salt=UUID.randomUUID().toString();
SimpleHash sh=new SimpleHash("MD5", user.getPassword(), salt, 1);
String newPassword=sh.toHex();
cookie中设置拦截
Cookie cookie = new Cookie("JT_TICKET",ticket);
cookie.setMaxAge(7*24*3600);
cookie.setDomain("jt.com"); //在jt.com中实现页面共享.
cookie.setPath("/"); //定于cookie的权限根目录有效
response.addCookie(cookie); //利用response将cookie保存到客户端中.
过滤器/拦截器 配置(扩展)
1 创建定义拦截器配置类 必须实现WebMvcConfigurer接口
将自己定义的拦截器类DI注入进来,并将拦截器类添加到拦截器中,并且添加拦截路径进拦截器
@Configuration //配置web.xml配置文件
public class MvcConfigurer implements WebMvcConfigurer{
//开启匹配后缀型配置,为了将来程序实现静态页面的跳转而准备的
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(true);
}
//添加拦截器配置
@Autowired
private UserInterceptor userInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor).addPathPatterns("/cart/**","/order/**"); //定义拦截路径
}
}
2 自己定义拦截器类 必须实现HandlerInterceptor(处理器拦截器接口) 如果用户已经登录则程序放行.否则拦截,拦截后判断是否含有令牌,及redis中获取user对象,获取到后存入request域对象或Threadlocal本地线程对象中
一定注意:用完request域对象或Threadlocal本地线程对象后必须移除,防止内存溢出!!
package com.jt.interceptor;
@Component //将拦截器交给Spring容器管理
public class UserInterceptor implements HandlerInterceptor {
@Autowired
private JedisCluster jedisCluster;
/**
* 返回值说明:
* boolean: true 放行
* : false 拦截 一般配合重定向的方式使用
* 业务说明:
* 如果用户已经登录则程序放行.否则拦截
* 判断依据: 1.是否有cookie 2.redis中是否有记录.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.动态获取JT_TICKET数据
String ticket = CookieUtil.getCookieValue("JT_TICKET",request);
if(!StringUtils.isEmpty(ticket)){
if(jedisCluster.exists(ticket)){
String userJSON = jedisCluster.get(ticket);
User user = ObjectMapperUtil.toObject(userJSON,User.class);
//当前的对象会携带当前的用户信息!!!! --利用request域对象传输数据
request.setAttribute("JT_USER",user);
//2.利用ThreadLocal的方式动态传参
UserThreadLocal.set(user);
return true; //表示放行
}
//3.将无效的cookie删除.
CookieUtil.deleteCookie("JT_TICKET","/","jt.com",response);
}
//重定向到用户的登录页面.
response.sendRedirect("/user/login.html");
return false;
}
/**
* 说明:利用拦截器方法清空数据
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//1.删除Request对象的数据
request.removeAttribute("JT_USER");
//2.删除ThreadLocal中的数据
UserThreadLocal.remove();
}
}
跨域
浏览器在解析ajax时,如果发现请求的协议名称 : //请求的域名:请求的端口号与网址的地址都相同的时满足同源策略的规定,浏览器可以正确的解析返回值.该访问称之为同域访问.该策略叫做同源策略.
但是如果违反了同源策略中的任意一条,则叫做跨域访问.浏览器出于安全性的考虑.不予解析返回值(请求正常的被处理,但是接收不到返回值).
JsonP
JSONP是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。-- 貌似JSONP 只可以发送 GET 请求
<script type="text/javascript">
$(function(){ //文档事件就绪函数
$.ajax({
url:"http://manage.jt.com/web/testJSONP",
type:"get", //jsonp只能支持get请求 src只能是get请求
dataType:"jsonp", //dataType表示返回值类型
//jsonp: "callback", //指定参数名称
//jsonpCallback: "hello", //指定回调函数名称
success:function (data){ //data经过jQuery封装返回就是json串
alert(data.itemId);
alert(data.itemDesc);
}
});
})
</script>
controller类中将数据对象转化为json加上字符串类型callback返回即可
或者直接使用工具类JSONPObject类对象,传入callback及需要返回的数据类型即可 --fasterxml组织提供的
@RequestMapping("/web/testJSONP")
public JSONPObject jsonp(String callback){
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(100L).setItemDesc("API测试!!!");
return new JSONPObject(callback, itemDesc);
}
CORS
首先在服务端创建CORS的配置类,添加响应信息,否则浏览器不支持数据的获取
配置类必须实现WebMvcConfigurer,设定允许可以跨域的请求路径,可以跨域的域名及跨域时是否允许携带cookie等
package com.jt.config;
@Configuration
public class CORSConfig implements WebMvcConfigurer {
/**
* 实现跨域的方式
* 需要配置服务端程序
* 方法说明:
* 1.addMapping(/**) 允许什么样的请求可以跨域 所有的请求
* 2.allowedOrigins("*")可以允许任意的域名
* 3.allowCredentials(true) 跨域时是否允许携带cookie等参数
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true);
}
}
设置完CORS配置类后,在其允许的域名及url请求地址范围内都可以跨域了,直接ajax跨域请求即可!!
HttpClient (微服务远程调用)
浏览器解析ajax发起跨域请求.程序虽然可以正确的调用,但是浏览器可以监控用户的所有的参数及返回值.在一些特定的条件下该操作不安全.
一般使用跨域的请求都是用来获取其他服务器的数据(查询操作),如果遇到了POST需要提交的参数应该使用更加安全的请求方式实现.
HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包
1 添加依赖
2 业务类里面直接创建HttpClient对象,创建HttpGet请求对象(指定远程调用url路径),使用HttpClient对象调用API的excute()方法执行get,返回HttpResponse响应对象,通过HttpResponse响应对象调用API方法getEntity方法()获取指定url路径的全部响应信息,利用EntityUtiles工具类(apache组织提供)toString()方法将获取的响应信息对象转化为String类型,这样可以方便展示了… --后面可以直接利用工具类ObjectMapper的readValue(Json类型数据对象,对象类型)转化为数据对象返回给前端等需要的地方即可!!
package com.jt.web;
@Service
public class UserServiceImpl implements UserService{
/**
* 步骤:
* 1.实例化httpClient工具API
* 2.定义请求url地址 任意网络地址....
* 3.定义请求的类型 get/post/put/delete
* 4.发起请求,获取响应的结果
* 5.判断响应的状态码信息. 200 404 500 406 400....
* 6.动态解析返回值执行后续操作.
*/
@Override
public User findUserById(Long userId) { //web前端服务器获取信息(id),远程调用sso单点登录查询出数据对象,HttpClient远程调用后获取了全部打响应信息(包括sso查询出的数据对象信息--接收时自动封装为String类型的Json),然后再将Json对象转化为数据对象即可
HttpClient httpClient = HttpClients.createDefault();
//String url = "https://www.baidu.com/";
String url = "http://sso.jt.com/user/findUserById/"+userId;
HttpGet get = new HttpGet(url);
try {
HttpResponse httpResponse = httpClient.execute(get);
//判断状态码是否正确
int statusCode = httpResponse.getStatusLine().getStatusCode();
if(statusCode == 200){ //表示请求正确
HttpEntity httpEntity = httpResponse.getEntity(); //获取服务器的全部响应信息(json/html/xml/xxxx)
String result = EntityUtils.toString(httpEntity,"UTF-8");
//获取之后可以执行业务处理......
System.out.println(result);
return ObjectMapperUtil.toObject(result, User.class); // ObjectMapperUtil自己写的封装了ObjectMapper工具类的对象,将Json转化为对象类型
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Dubbo框架 (微服务框架)
Dubbo框架RPC远程过程调用,三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现
1 提供者,消费者及第三方接口pom文件都要加载dubbo的依赖 --父级工程直接都继承自父级即可(父级pom文件中加载dubbo依赖)
2 定义第三方的dubbo接口 编写Dubboservice接口
3 定义服务提供者服务器yml文件中配置dubbo(只配置dubbo包扫描,定义应用名称,指定连接注册中心,指定传输协议及dubbo传输服务的端口) service层serviceImpl实现类上添加**@Service**(这是dubbo框架的注解)并实现dubbo框架里的第三方接口即可
4 定义服务消费者服务器yml文件中配置dubbo(只需要配置dubbo包扫描,定义应用名称,指定连接注册中心)即可 controller层添加**@Reference()注解**–这是dubbo框架提供的注解DI依赖注入第三方接口类型对象即可 直接去调用提供者的服务器了!!
nginx反向代理服务器
Linux安装
解压
安装
修改nginx.conf配置文件
./nginx 运行nginx
RedisCluster缓存集群
1 解压
2 安装reids
3 修改redis配置文件redis.conf
4 启动redis
redis-server redis.conf
5 进入客户端
redis-cli -p 6379
关闭redis
kill -9 进程id(PID)
redis-cli -p 6379 shutdown
==redis集群搭建
1 为每个redis创建自己的文件夹
2 复制redis.conf到其中一个文件夹(修改好配置其他文件夹直接复制即可)
3 编辑配置文件redis.conf
4 复制修改后的配置文件到每一个redis集群文件夹中
5 修改每一个文件夹中的该配置文件改为对应自己的端口
:%s/7000/7001/g --将文件中的7000全部修改为7001
6 创建启动脚本 #!/bin/sh
7 启动所有redis节点
8 执行创建redis集群命令,中间不能有回车换行符
redis-cli --cluster create --cluster-replicas 1 192.168.35.130:7000 192.168.35.130:7001 192.168.35.130:7002 192.168.35.130:7003 192.168.35.130:7004 192.168.35.130:7005
Redis支持5种数据类型
字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets)
Redis中持久化策略(RDB AOF)
Redis内存优化策略
1.volatile-lru 在设定了超时时间的数据中,采用lru算法.
2.allkeys-lru 所有数据采用lru算法
3.volatile-lfu 在超时的数据中采用lfu算法
4.allkeys-lfu -> 所有数据采用lfu算法
5.volatile-random -> 设定超时时间的数据采用随机算法
6.allkeys-random -> 所有数据随机删除
7.volatile-ttl -> 删除存活时间少的数据
8.noeviction -> 不会删除数据,如果内存溢出报错返回.
SpringBoot 整合 redisClust
1 添加依赖
2 编辑定义properties配置文件
ip:端口,ip:端口,…
3 编辑定义Jedis配置类
@Configuration
@PropertySource(“classpath:/properties/redis.properties”) //引入配置文件
@Value("${redis.nodes}") //获取配置文件中的节点配置(字符串)
@Bean //实例化集群的对象交给Spring容器管理 --获取配置类里的redis节点获取到每个节点的ip和port存入Set 集合中将set集合存入JedisCluster(set)中
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig{
@Value("${redis.nodes}")
private String nodes;
@Bean
public JedisCluster jedisCluster(){
Set<HostAndPort> set = new HashSet<>();
String[] nodeArray = nodes.split(",");
for(String node:nodeArray){
String[] nodeTemp = nodes.split(":");
String host = nodeTemp[0];
int port = Integer.paresInt(nodeTemp[1]);
HostAndPort hostAndPort = new HostAndPort(host,port);
set.add(hostAndPort);
}
return new JedisCluster(set);
}
}
4 在AOP切面类中注入redisCluster集群对象,就实现了在切面中加入到缓存中
Mycat数据库服务器
实现主从复制,读写分离,负载均衡
1 两台Linux服务器均安装数据库并分别配置my.cnf配置文件,服务id和开启二进制文件的读取
2 数据库分别执行互相挂载的命令
3 安装mycat服务器实现数据库高可用,编辑server.xml文件及schema配置文件
AOP
1 添加依赖
2 定义切面类加@Aspect注解及@Component交给spring容器管理
3 添加切入点方法(不添加,直接将切入点表达式写在通知注解上也可以)用@Pointcut(“切入点表达式”)
4 编写功能扩展方法添加通知注解@Around(“切入点方法或者切入点表达式”)
Shiro安全框架
三个主要对象 --Subject,SecurityManager,Realm
SecurityManager的核心对象:::Authenticator认证管理对象,Authorizer授权管理对象,SessionManager会话管理对象,CacheManager缓存管理对象,Cryptography加密管理对象以及Realms领域对象(领域对象:负责处理认证和授权领域的数据访问题)
开启项目模式–认证业务:
1 pom文件添加shiro依赖
2 创建SpringShiroConfig配置类
2.1 添加@Configuration–描述该类为一个配置类并交给spring容器管理
2.2 配置类中添加SecurityManager对象(@Bean注解并且该对象一定要使用org.apache.shiro.mgt.SecurityManager这个接口对象)若不添加Realm,CacheManager,RememberMeManager,SessionManager对象参数就直接只创建出来即可,但一般最少都需要添加上Realm!!
2.3 配置类中添加ShiroFilterFactoryBean对象的配置(添加@Bean),创建ShiroFilterFactoryBean对象,调用方法将securityManager传入ShiroFilterFactoryBean对象中,并且必须调用方法将认证页面(登录页面)设置上,LinkedHashMap对象map指定请求过滤规则(哪些允许访问,哪些必须认证才能访问,并且指定登录页面匿名访问,登出必须指定为logout)然后调用方法将该map对象传入ShiroFilterFactoryBean对象中即可)
3 登录controller中添加呈现登录页面的方法
4 dao中添加根据用户名获取用户对象的方法
5 mapper中编写sql语句查询数据库对应表的数据(用户对象)封装到pojo类中
6 service层直接在自己编写的Realm(就可以把Realm看成是service)中实现,该Realm必须继承AuthorizingRealm抽象类然后DI依赖注入dao对象,调用dao查询数据库操作
6.1 Realm类中设置凭证匹配器,里面构建匹配器对象,为该匹配器对象设置加密算法(“MD5”),设置加密次数将该匹配器对象作为参数使用super传给父类
6.2 重写获取认证方法的方法,通过此方法完成认证数据的获取及封装,后将数据返回给认证管理器完成认证操作(里面通过token对象获取用户名,根据用户名dao查询数据库获取用户对象,对user对象进行参数判断(是否为空,权限是否被禁用)封装用户信息(salt盐值),创建认证信息对象,将user对象,密码,封装的盐值,realmName,返回该认证信息对象即可) --重写授权方法,完成授权操作
7 该Realm类添加到SpringShiroConfig配置类中(以方法传参的方式传入后securityManager对象调用方法将realm对象属性设置进自己的对象中)
8 controller类实现
添加方法处理客户端登录请求,获取用户名,密码等然后提交给shiro框架进行认证
使用SecurityUtils工具获取subject对象,创建token对象封装用户名及密码,使用subject对象提交封装了用户信息的token对象,返回一个JsonResult的msg响应信息即可
9 将用户登录这个路径添加到shiroFilterFactory安全过滤器工厂对象中( map.put("/user/doLogin",“anon”);)设置成可以匿名访问即可
10 优化可以对异常信息统一处理在全局异常处理类中(该类添加@ControllerAdvice,@ResponseBody注解,方法上添加@ExceptionHandler()参数指明处理异常的类型用两目运算instanceof判断异常类型是否为shiro框架的异常类型)
11 认证的客户端实现就是将用户名和密码参数提交到服务端
退出操作只需要SpringShiroConfig配置类中配置ShiroFilterFactoryBean shrio过滤器工厂对象的( map.put("/doLogout",“logout”);)即可
授权业务 --认证业务完成的前提下登录进去了才能授权,
1 SpringShiroConfig配置类中添加授权配置,配置advisor对象,shiro框架底层会通过此对象的matchs方法返回值(类似切入点)决定是否创建代理对象,进行权限控制(该对象里SecurityManager作为参数传入方法中,创建一个授权属性资源顾问对象,调用方法将sercurityManager对象设置进去,返回该顾问对象即可)
2 dao中基于登陆用户ID,获取登陆用户的权限信息,并进行封装
2.1 在SysUserRoleDao中定义基于用户id查找角色id的方法
2.2 在SysRoleMenuDao中定义基于角色id查找菜单id的方法
2.3 在SysMenuDao中基于菜单id查找权限标识的方法
3 mapper文件中分别在以上三个mapper文件中执行对应的sql语句
4 service层–在ShiroUserReam类中,重写对象realm的doGetAuthorizationInfo方法,并完成用户权限信息的获取以及封装,最后将信息传递给授权管理器完成授权操作
该Realm类就是类似于serviceImpl类,添加@Service注解并必须继承AuthorizingRealm抽象类,DI依赖注入需要的几个对象,重写的获取授权信息对象的方法中根据传来的参数主要的负责体对象调用方法获取user对象,通过user对象获取id,基于用户id获取所拥有的角色id(List集合),通过角色id获取菜单id(List集合),在基于菜单id获取菜单上的权限标识(查询sys_menus表)这是一个List集合,而AuthorizationInfo授权信息对象只能封装set集合,这里将查询出来的菜单权限标识List集合foreach遍历一个个取出后放入set集合中,然后将该封装了该用户对应的菜单上的权限标识的set集合封装到AuthorizationInfo授权信息对象中,返回该信息对象即可
5 授权访问实现描述
在需要进行授权访问的业务层(Service)方法上,添加执行此方法需要的权限标识–该标识须于数据库表中的授权标识对应(例如:在数据库表中根据用户查询出菜单表上该用户所具有的所有授权标识,而本次该用户访问的方法上也有一个授权标识,若该用户的所有标识中有本次方法的授权标识,则可以访问该方法(修改权限等操作),若该用户所具有的所有授权标识中与该方法上授权标识没有一致的,则该用户不能访问该方法)
shiro缓存业务实现
1 :在SpringShiroConfig中配置缓存对象(@Bean)–注意名字不能是cacheManager,因为spring容器中已经存在一个名字为cacheManager的对象了
2 修改securityManager的配置,将缓存对象注入给SecurityManager对象
3 启动类上添加@EnableCaching注解启动缓存即可实现了shiro框架的缓存功能!!!
shiro记住我实现 --服务端代码
1 在SysUserController中的doLogin方法中基于是否选中记住我,设置token的setRememberMe方法
创建token对象封装用户信息(username,password)
判断若选中rememberMe则将token的rememberMe设置为true
创建提交用户信息的subject对象,通过该对象将封装有user信息的token对象提交给底层的securityManager
2 在SpringShiroConfig配置类中添加记住我配置(@Bean)创建cookie的记住我管理器对象,创建一个简单cookie对象设置名字为rememberMe,设置cookie的生命周期,通过cookie记住我管理器对象将cookie对象设置进来,并将该对象返回即可
3 在SpringShiroConfig中修改securityManager的配置,为securityManager注入RememberMeManager 对象
4 修改shiro的过滤认证级别,将/=author修改为/ =user --(map.put("/**",“user”)
shiro会话管理设置
1 在SpringShiroConfig类中,添加会话管理器配置(@Bean)创建默认的web会话管理器对象,设置该对象的全局会话超时时间,返回该对象即可
2 :在SpringShiroConfig配置类中,对安全管理器 securityManager 增加 sessionManager值的注入即可
数据库优化
sql优化:
1 合理使用索引(索引少了查询慢,多了占用空间大的特点,增删改时动态维护索引,影响性能)
2 union all代替union(因为union需要排重及对数据排序)
3 不要写select * 语句
4 一般join字段都要加上索引
5 避免复杂sql语句,使用多个短查询
6 避免where 1=1写法
7 避免order by rand()类似写法 --RAND()导致数据列被多次扫描
数据库索引
索引分为:
维度一:
聚集索引和非聚集索引
聚集索引是将索引单独一列存入原先数据库表中
非聚集索引就是将索引列单独拿出来存入一张表中
维度二:
简单索引
唯一索引(unique) --联合查询时时union,去重distinct(查询时字段名前面加上该关键字即可)
主键索引
联合索引(多字段逗号隔开)
全局索引(几乎不用)
空间索引(几乎不用)
建立索引的原则:
1 定义主键的数据列一定要建立索引。
2 定义有外键的数据列一定要建立索引。
3 对于经常查询的数据列最好建立索引。
4 对于需要在指定范围内的快速或频繁查询的数据列;
5 经常用在WHERE子句中的数据列。
6 经常出现在关键字order by、group by、distinct后面的字段,建立索引。如果建立的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致,否则索引不会被使用。
7 对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。
8 对于定义为text、image和bit的数据类型的列不要建立索引。
9 对于经常存取的列避免建立索引
10 限制表上的索引数目。对一个存在大量更新操作的表,所建索引的数目一般不要超过3个,最多不要超过5个。索引虽说提高了访问速度,但太多索引会影响数据的更新操作。
11 对复合索引,按照字段在查询条件中出现的频度建立索引。在复合索引中,记录首先按照第一个字段排序。对于在第一个字段上取值相同的记录,系统再按照第二个字段的取值排序,以此类推。因此只有复合索引的第一个字段出现在查询条件中,该索引才可能被使用,因此将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的作用。
唯一的索引 (Unique Index)
CREATE UNIQUE INDEX 索引名称 ON 表名称 (列名称)
create unique index 索引名 on 表名(列名)
简单的索引
create index 索引名称 on 表名(列名)
create index PersonIndex on persion(LastName)
降序索引某个列中的值
create index PersonIndex on persion(LastName desc)
索引不止一个列,逗号隔开 --联合索引
create index PersonIndex on persion(LastName , FirstName)
数据库最左原则
最左优先,以最左边的为起点任何连续的索引都能匹配上
最左匹配原则都是针对联合索引来说的
数据库依据联合索引最左的字段来构建B+树
事务四大隔离级别:
SSM
ssm
spring DI ioc控制反转aop
springmvc
1、客户端发送请求
2、前端控制器 DispatcherServlet 接受客户端请求
3、找到处理器映射 HandlerMapping 解析请求对应的 Handler
4、HandlerAdapter 会根据 Handler 来调用真正的处理器开处理请求,并处理相应的业务逻辑
5、处理器返回一个模型视图 ModelAndView
6、视图解析器进行解析
7、返回一个视图对象
8、前端控制器 DispatcherServlet 渲染数据(Moder),将得到视图对象返回给用户
mybatis优秀的持久层框架
封装jdbc与数据库交互
dubbo框架微服务RPC远程调用
1 提供者,消费者及第三方接口pom文件都要加载dubbo的依赖 --父级工程直接都继承自父级即可(父级pom文件中加载dubbo依赖)
2 定义第三方的dubbo接口 编写Dubboservice接口
3 定义服务提供者服务器yml文件中配置dubbo(只配置dubbo包扫描,定义应用名称,指定连接注册中心,指定传输协议及dubbo传输服务的端口) service层serviceImpl实现类上添加**@Service**(这是dubbo框架的注解)并实现dubbo框架里的第三方接口即可
4 定义服务消费者服务器yml文件中配置dubbo(只需要配置dubbo包扫描,定义应用名称,指定连接注册中心)即可 controller层添加**@Reference()注解**–这是dubbo框架提供的注解DI依赖注入第三方接口类型对象即可 直接去调用提供者的服务器了!!
SpringCloud微服务的工具集
后面一定要总结补上!!!
docker容器化技术及DevOps开发运维一体化技术
Kubernetes,k8s容器自动化部署,一键搭建集群技术
HashMap,HashTable,TreeMap区别和用法
1 Hashmap 是根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。线程不同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致,HashMap允许key值只能由一个null值,数组的默认大小是16
2 HashTable的方法是同步的,不允许null值,数组默认大小是11,貌似HashTable直接使用对象的hashCode做为键
3 TreeMap能够把它保存的记录根据键排序,默认是按升序排序
JSP九大隐式对象及四大作用域
九大隐式对象
request response session application
out config page pageContext
exception
四大作用域
pageContext
request
session
application
分布式架构与微服务架构的区别
微服务重在解耦合,使每个模块都独立。分布式重在资源共享与加快计算机计算速度。
分布式:分散压力。微服务:分散能力
貌似微服务就是更加细微及专注于一个个单独功能模块的分布式架构 --分布式目的仅仅只是为了分散服务器压力
Ajax(局部刷新,异步通讯)
基于XHR对象(XMLHttpRequest对象)实现监听,回调函数接收数据获取响应结果,创建与服务端连接,发送异步请求与服务端通讯.
jQuery中的Ajax应用
ajax(…)
get(…)
getJSON(…)
post(…)
load()
get函数应用
//向服务端发送Ajax Get 请求
function doGet(){
//1.定义请求的url
var url="doAjaxGet";
//2.定义请求的参数
var params="msg=hello jquery ajax get";
//3.发送异步Get请求
//这里的$符号为jQuery中的一个对象
//get(url[,params][,callback][,dataType])为jquery中的一个ajax函数
$.get(url,params,function(result){
//document.getElementById("result").innerHTML=result;
$("#result").html(result);
},"text");//在这个函数中你看到ajax的代码了吗?
}
post函数应用
//向服务端发送Ajax Post 请求
function doPost(){
//1.定义请求的url
var url="doAjaxPost";
//2.定义请求的参数
var params="msg=hello jquery ajax Post";
//3.发送异步POST请求
//这里的$符号为jQuery中的一个对象
//post(url[,params][,callback][,dataType])为jquery中的一个ajax函数
$.post(url,params,function(result){//post请求一般用于向服务端提交数据
$("#result").html(result);
});//在这个函数中你看到ajax的代码了吗?
}
ajax函数应用 --这才是Ajax学习使用的重重点!!
//向服务端发送Ajax Post 请求
function doAjax(){
//1.定义请求的url
var url="doAjaxGet";
//2.定义请求的参数
var params="msg=hello jquery ajax request";
//3.发送异步Get请求
//这里的$符号为jQuery中的一个对象
$.ajax({
type:"GET",//表示get请求(默认为get),省略不写为Get
url:url,//":"左边的内容为语法定义,我们不能修改.":"右边为我们自己定义
data:params,//请求参数
async:true,//true表示异步
success:function(result){ //回调函数
$("#result").html(result);
}
});//在这个函数中你看到ajax的代码了吗?
}
load函数应用
function doLoad(){
//1.定义请求的url
var url="doAjaxGet";
//2.定义请求的参数
var params="msg=hello jquery ajax request";
//3.发送异步Get请求
//在指定位置异步加载url对象的资源,
//在当前应用中表示把url对象的资源呈现到#result位置.
//$("#result").load(url,params,function(){//回调函数,资源加载完成执行此函数
// console.log("load complete");
//});
$("#result").load(url);//假如不向服务端传值,不需要处理load完以后的结果,还可以这样写
}