最后
ActiveMQ消息中间件面试专题
- 什么是ActiveMQ?
- ActiveMQ服务器宕机怎么办?
- 丢消息怎么办?
- 持久化消息非常慢怎么办?
- 消息的不均匀消费怎么办?
- 死信队列怎么办?
- ActiveMQ中的消息重发时间间隔和重发次数吗?
ActiveMQ消息中间件面试专题解析拓展:

redis面试专题及答案
- 支持一致性哈希的客户端有哪些?
- Redis与其他key-value存储有什么不同?
- Redis的内存占用情况怎么样?
- 都有哪些办法可以降低Redis的内存使用情况呢?
- 查看Redis使用情况及状态信息用什么命令?
- Redis的内存用完了会发生什么?
- Redis是单线程的,如何提高多核CPU的利用率?

Spring面试专题及答案
- 谈谈你对 Spring 的理解
- Spring 有哪些优点?
- Spring 中的设计模式
- 怎样开启注解装配以及常用注解
- 简单介绍下 Spring bean 的生命周期
Spring面试答案解析拓展

高并发多线程面试专题
- 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
- Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
- Java 中 wait 和 sleep 方法有什么区别?
- 如何在 Java 中实现一个阻塞队列?
- 如何在 Java 中编写代码解决生产者消费者问题?
- 写一段死锁代码。你在 Java 中如何解决死锁?
高并发多线程面试解析与拓展

jvm面试专题与解析
- JVM 由哪些部分组成?
- JVM 内存划分?
- Java 的内存模型?
- 引用的分类?
- GC什么时候开始?
JVM面试专题解析与拓展!

//openId是通过使用accessToken请求时获取到的,所以构造函数的形参中要加入accessToken,appId是QQ服务提供商提供给你的,你这个系统的Id,也需要传入
public QQImpl(String accessToken, String appId) {
//父类会自动将accessToken放到请求url后面作为请求参数
super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
this.appId = appId;
//String.format用来将请求中的%s用accessToken替换掉
String url = String.format(URL_GET_OPENID,accessToken);
//发送HTTP请求获取openId,返回的是JSON数据: callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} );
String result = getRestTemplate().getForObject(url,String.class);
System.out.println(result);
this.openId = StringUtils.substringBetween(result,"\"openid\":","}");
}
/**
* 2、使用 access_token,appid,openid来获取用户信息
* @return
* @throws Exception
*/
@Override
public QQUserInfo getUserInfo() throws Exception{
//因为在构造函数中super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);已经将accessToken加到请求中,所以这里就没有再加accessToken参数
String url = String.format(URL_GET_USERINFO,appId,openId);
//获取用户信息
String result = getRestTemplate().getForObject(url,String.class);
System.out.println(result);
//objectMapper.readValue()是将字符串转为对象
QQUserInfo userInfo = objectMapper.readValue(result,QQUserInfo.class);
return userInfo;
}
}
QQ的登录具体流程可到 :**[https://wiki.connect.qq.com/准备工作\_oauth2-0]( )** 查看。
Step1:获取Authorization Code
**请求地址**:https://graph.qq.com/oauth2.0/authorize
**Step2:通过Authorization Code获取Access Token**
**请求地址**:https://graph.qq.com/oauth2.0/token
**Step3:获取用户OpenID**
**请求地址:**https://graph.qq.com/oauth2.0/me
**Step4:获取用户信息**
**请求地址:**https://graph.qq.com/user/get\_user\_info
### 3.2 **ServiceProvider封装获取授权码、令牌和用户信息**
package security.core.social.qq.connect;
import org.springframework.social.oauth2.AbstractOAuth2ServiceProvider;
import org.springframework.social.oauth2.OAuth2Operations;
import org.springframework.social.oauth2.OAuth2Template;
import security.core.social.qq.api.QQ;
import security.core.social.qq.api.QQImpl;
/**
-
QQ登录时的ServiceProvider
*/
public class QQServiceProvider extends AbstractOAuth2ServiceProvider {private String appId;
//1、第三方应用将用户带到服务提供商的URL获取授权码
private static final String URL_AUTHORIZE = “https://graph.qq.com/oauth2.0/authorize”;//2、第三方应用拿着授权码获取令牌的URL
private static final String URL_ACCESS_TOKEN = “https://graph.qq.com/oauth2.0/token”;public QQServiceProvider(String appId,String appSecret) {
super(new OAuth2Template(appId,appSecret,URL_AUTHORIZE,URL_ACCESS_TOKEN));
}/**
- 获取QQ的实现类
- @param accessToken
- @return
*/
@Override
public QQ getApi(String accessToken) {
return new QQImpl(accessToken,appId);
}
}
### 3.3新建 ApiAdapter的实现类QQAdapter
package security.core.social.qq.connect;
import org.springframework.social.connect.ApiAdapter;
import org.springframework.social.connect.ConnectionValues;
import org.springframework.social.connect.UserProfile;
import security.core.social.qq.api.QQ;
import security.core.social.qq.api.QQUserInfo;
/**
-
ApiAdapter里的泛型是要适配接口,这里是QQ
*/
public class QQAdapter implements ApiAdapter {/**
- 测试QQ接口是否可用
- @param qq
- @return
*/
@Override
public boolean test(QQ qq) {
return true;
}
/**
-
数据适配:将QQ接口获取到的数据转换成Connection里标准数据
-
@param qq
-
@param connectionValues
*/
@Override
public void setConnectionValues(QQ qq, ConnectionValues connectionValues) {
QQUserInfo userInfo = qq.getUserInfo();connectionValues.setDisplayName(userInfo.getNickname());
connectionValues.setImageUrl(userInfo.getFigureurl_qq_1());
//个人主页:QQ是没有个人主页的,设为null
connectionValues.setProfileUrl(null);
connectionValues.setProviderUserId(userInfo.getOpenId());
}
/**
- 获取用户主页信息,暂时用不到
- @param qq
- @return
*/
@Override
public UserProfile fetchUserProfile(QQ qq) {
return null;
}
/**
- 更新QQ信息(用不到,QQ无此功能)
- @param qq
- @param s
*/
@Override
public void updateStatus(QQ qq, String s) {
}
}
### 3.3 新建ConnectionFacotory并继承OAuth2Connection
package security.core.social.qq.connect;
import org.springframework.social.connect.support.OAuth2ConnectionFactory;
import security.core.social.qq.api.QQ;
/**
-
QQConnectionFactory继承OAuth2ConnectionFactory的泛型是要适配的接口,作用是用来生成Connection
*/
public class QQConnectionFactory extends OAuth2ConnectionFactory {/**
- QQConnectionFactory的构造函数
- @param providerId
- @param appId
- @param appScret
/
public QQConnectionFactory(String providerId,String appId,String appScret) {
/*- providerId:服务提供商的唯一标识
- serviceProvider:QQServiceProvider
- apiAdapter:QQAdapter
*/
super(providerId, new QQServiceProvider(appId,appScret), new QQAdapter());
}
}
### 3.4 新建一个配置类SocialConfig,使用springsocial的配置将从第三方获取到的用户数据存储到数据库中
package security.core.social;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.social.config.annotation.EnableSocial;
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository;
import javax.sql.DataSource;
/**
-
SocialConfig:用于将从第三方获取到的用户数据存储到数据库中
-
EnableSocial:将项目的social特性开启起来
*/
@Configuration
@EnableSocial
public class SocialConfig extends SocialConfigurerAdapter {@Autowired
private DataSource dataSource;/**
- JdbcUsersConnectionRepository构造函数的三个参数的作用:
- dataSource:用于连接数据库
- connectionFactoryLocator:用于查找具体使用的ConnectionFactoryLocator
- textEncryptor:用于加解密数据
- @param connectionFactoryLocator
- @return
*/
@Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
//Encryptors.noOpText():是不做任何加解密
return new JdbcUsersConnectionRepository(dataSource,connectionFactoryLocator, Encryptors.noOpText());
}
}
### 3.5 将 JdbcUsersConnectionRepository使用的数据表的建表语句拿到数据库里执行建表,建表语句在**JdbcUsersConnectionRepository**类的旁边

### 3.6给新建的数据表加入前缀
/**
* JdbcUsersConnectionRepository构造函数的三个参数的作用:
* dataSource:用于连接数据库
* connectionFactoryLocator:用于查找具体使用的ConnectionFactoryLocator
* textEncryptor:用于加解密数据
* @param connectionFactoryLocator
* @return
*/
@Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
//Encryptors.noOpText():是不做任何加解密
JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(dataSource,connectionFactoryLocator, Encryptors.noOpText());
//setTablePrefix:设置表的前缀
repository.setTablePrefix("u_");
return repository;
}
完整代码:
package security.core.social;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.social.config.annotation.EnableSocial;
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository;
import javax.sql.DataSource;
/**
-
SocialConfig:用于将从第三方获取到的用户数据存储到数据库中
-
EnableSocial:将项目的social特性开启起来
*/
@Configuration
@EnableSocial
public class SocialConfig extends SocialConfigurerAdapter {@Autowired
private DataSource dataSource;/**
- JdbcUsersConnectionRepository构造函数的三个参数的作用:
- dataSource:用于连接数据库
- connectionFactoryLocator:用于查找具体使用的ConnectionFactoryLocator
- textEncryptor:用于加解密数据
- @param connectionFactoryLocator
- @return
*/
@Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
//Encryptors.noOpText():是不做任何加解密
JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(dataSource,connectionFactoryLocator, Encryptors.noOpText());
//setTablePrefix:设置表的前缀
repository.setTablePrefix(“u_”);
return repository;
}
}
### 3.7 使用 userId获取用户信息
修改**MyUserDetailsService**,加入实现**SocialUserDetailsService**,用于通过userId来获取用户信息
package security.browser.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.social.security.SocialUser;
import org.springframework.social.security.SocialUserDetails;
import org.springframework.social.security.SocialUserDetailsService;
import org.springframework.stereotype.Component;
/**
-
SocialUserDetailsService:是social的获取用户信息的接口类
*/
@Component
@Slf4j
public class MyUserDetailsService implements UserDetailsService, SocialUserDetailsService {@Autowired
private PasswordEncoder myPasswordEncoder;
/**-
可以@AutowiredDao层接口从而实现根据用户名去查找用户信息
-
@param username
-
@return
-
@throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("用户名: "+username);String password = myPasswordEncoder.encode(“123456”);
log.info(“密码:”+password);//这个User类实现了UserDetails
//密码应该是数据库查询出的密码
//authorities:用户权限的集合,即用来给用户授权
User user = new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList(“admin”));return user;
}
/**
-
通过userId获取用户信息
-
@param userId
-
@return
-
@throws UsernameNotFoundException
*/
@Override
public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException {
log.info("用户Id: "+userId);String password = myPasswordEncoder.encode(“123456”);
log.info(“密码:”+password);//这个User类实现了UserDetails
//密码应该是数据库查询出的密码
//authorities:用户权限的集合,即用来给用户授权
return new SocialUser(userId,password, AuthorityUtils.commaSeparatedStringToAuthorityList(“admin”));
}
}
-
#### 3.8新建QQProperties的相关配置类
package security.core.properties;
/**
-
QQ登录的相关配置
*/
public class QQProperties{/**
- 从服务提供商处申请的本项目的appId
*/
private String appId;
/**
- 从服务提供商处申请的本项目的appSecret
*/
private String appSecret;
/**
- 服务提供商的标识
*/
private String provideId = “qq”;
public String getAppId() {
return appId;
}public void setAppId(String appId) {
this.appId = appId;
}public String getAppSecret() {
return appSecret;
}public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}public String getProvideId() {
return provideId;
}public void setProvideId(String provideId) {
this.provideId = provideId;
}
} - 从服务提供商处申请的本项目的appId
### 3.9 新建SocialProperties相关的配置类
package security.core.properties;
/**
-
社交相关的配置类
*/
public class SocialProperties {private QQProperties qq = new QQProperties();
public QQProperties getQqProperties() {
return qq;
}public void setQqProperties(QQProperties qq) {
this.qq = qq;
}
}
### 3.10 在SecurityProperties中加入SocialProperties配置
/**
* 社交相关的配置
*/
private SocialProperties social = new SocialProperties();
public SocialProperties getSocial() {
return social;
}
public void setSocial(SocialProperties social) {
this.social = social;
}
完整代码:
package security.core.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource(“classpath:application-browser.properties”)
//@PropertySource(value= {“classpath:application-demo.properties”,“classpath:application-browser.properties”})
@ConfigurationProperties(“imooc.security”)
public class SecurityProperties {
/**
* 浏览器相关的配置
*/
private BrowserProperties browser = new BrowserProperties();
/**
* 验证码相关的配置
*/
private ValidateCodeProperties code = new ValidateCodeProperties();
/**
* 社交相关的配置
*/
private SocialProperties social = new SocialProperties();
public BrowserProperties getBrowser() {
return browser;
}
public void setBrowser(BrowserProperties browser) {
this.browser = browser;
}
public ValidateCodeProperties getCode() {
return code;
}
public void setCode(ValidateCodeProperties code) {
this.code = code;
}
public SocialProperties getSocial() {
return social;
}
public void setSocial(SocialProperties social) {
this.social = social;
}
}
### 3.11 新建SocialAutoConfigurerAdapter,因为使用的SpringSocial中没有SocialAutoConfigurerAdapter,所以新建一个
package security.core.social.qq.config;
import org.springframework.core.env.Environment;
import org.springframework.social.config.annotation.ConnectionFactoryConfigurer;
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
import org.springframework.social.connect.ConnectionFactory;
/**
- 因为使用的SpringSocial中没有SocialAutoConfigurerAdapter,所以新建一个
*/
public abstract class SocialAutoConfigurerAdapter extends SocialConfigurerAdapter {
public SocialAutoConfigurerAdapter() {
}
public void addConnectionFactories(ConnectionFactoryConfigurer configurer, Environment environment) {
configurer.addConnectionFactory(this.createConnectionFactory());
}
protected abstract ConnectionFactory<?> createConnectionFactory();
}
### 3.12 新建 QQAutoConfig,用于将QQ的配置注入到ConnectionFactory的构造参数中
package security.core.social.qq.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.social.connect.ConnectionFactory;
import security.core.properties.QQProperties;
import security.core.properties.SecurityProperties;
import security.core.social.qq.connect.QQConnectionFactory;
/**
- 用于将QQ的配置注入到ConnectionFactory的构造参数中
- ConditionalOnProperty:作用是只有当系统中配置了appId时QQAutoConfig配置类才会生效
*/
@Configuration
@ConditionalOnProperty(value = “imooc.security.social.qq”,name = “appId”)
public class QQAutoConfig extends SocialAutoConfigurerAdapter{
@Autowired
private SecurityProperties securityProperties;
/**
* 在创建ConnectionFactory时将参数注入进去
* @return
*/
@Override
protected ConnectionFactory<?> createConnectionFactory() {
QQProperties qqconfig = securityProperties.getSocial().getQqProperties();
return new QQConnectionFactory(qqconfig.getProvideId(),qqconfig.getAppId(),qqconfig.getAppSecret());
}
}
### 3.13 在application-browser.properties属性文件中加入
imooc.security.social.qq.appId =
imooc.security.social.qq.appSecret =
### 3.14 在过滤器链中加入SocialAuthenticationFilter过滤器
#### 3.14.1、将SpringSocial的Bean写在**SocialConfig**中
/**
* SpringSocial的配置,这个Bean也可以挪到 BrowserSecurityConfig里
* @return
*/
@Bean
public SpringSocialConfigurer imoocSecuritySocialConfig(){
return new SpringSocialConfigurer();
}
#### 3.14.2、在SpringSecurity的过滤器链中加入SpringSocial的配置
//加入SpringSocialConfigurer的配置
@Autowired
private SpringSocialConfigurer socialConfigurer;
/************************************************/
.apply(socialConfigurer).and()//将SpringSocial的过滤器配置加入其中
BrowserSecurityConfig的完整代码:
package security.browser.config;
import imooc.security.msn.service.MessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.social.security.SpringSocialConfigurer;
import security.core.authentication.handle.MsnCodeAuthenticationFailureHandler;
import security.core.authentication.handle.MsnCodeAuthenticationSuccessHandler;
import security.core.authentication.mobile.MsnCodeAuthenticationSecurityConfig;
import security.core.properties.SecurityProperties;
import security.core.validateCode.ImageCodeGenerator;
import security.core.validateCode.ValidateCodeFilter;
import security.core.validateCode.ValidateCodeGenerator;
import javax.sql.DataSource;
/**
-
WebSecurityConfigurerAdapter是SpringSecurity提供的安全适配器类
*/
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {/**
- 读取配置信息
*/
- 读取配置信息
面试资料整理汇总


这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。
面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了
在这里祝大家能够拿到心仪的offer!
teCode.ValidateCodeFilter;
import security.core.validateCode.ValidateCodeGenerator;
import javax.sql.DataSource;
/**
-
WebSecurityConfigurerAdapter是SpringSecurity提供的安全适配器类
*/
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {/**
- 读取配置信息
*/
- 读取配置信息
面试资料整理汇总
[外链图片转存中…(img-sP1xvSgp-1715470538278)]
[外链图片转存中…(img-x039FDyc-1715470538279)]
这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。
面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了
在这里祝大家能够拿到心仪的offer!

1259

被折叠的 条评论
为什么被折叠?



