为MongoDB定制Spring Social Connect框架

在上一篇文章中 ,我谈到了我面临的第一个挑战是更改数据模型并添加连接框架。 在这里,我想提供有关我如何做的更多细节。 Spring Social项目已经提供了基于jdbc的连接存储库实现,以将用户连接数据持久保存到关系数据库中。 但是,我使用的是MongoDB,因此我需要自定义代码,并且发现这样做相对容易。 用户连接数据将保存为UserSocialConnection的对象,它是一个MongoDB文档:

@SuppressWarnings('serial')
@Document(collection = 'UserSocialConnection')
public class UserSocialConnection extends BaseEntity {private String userId;private String providerId;private String providerUserId;private String displayName;private String profileUrl;private String imageUrl;private String accessToken;private String secret;private String refreshToken;private Long expireTime;//Getter/Setter omitted.public UserSocialConnection() {super();}public UserSocialConnection(String userId, String providerId, String providerUserId, int rank,String displayName, String profileUrl, String imageUrl, String accessToken, String secret,String refreshToken, Long expireTime) {super();this.userId = userId;this.providerId = providerId;this.providerUserId = providerUserId;this.displayName = displayName;this.profileUrl = profileUrl;this.imageUrl = imageUrl;this.accessToken = accessToken;this.secret = secret;this.refreshToken = refreshToken;this.expireTime = expireTime;}
}

BaseEntity仅具有“ id”。 在Spring Data项目的帮助下,我不需要为UserSocialConnection编写任何CRUD操作代码,只需扩展MongoRepository

public interface UserSocialConnectionRepository extends MongoRepository<UserSocialConnection, String>{List<UserSocialConnection> findByUserId(String userId);List<UserSocialConnection> findByUserIdAndProviderId(String userId, String providerId);List<UserSocialConnection> findByProviderIdAndProviderUserId(String providerId, String providerUserId);UserSocialConnection findByUserIdAndProviderIdAndProviderUserId(String userId, String providerId, String providerUserId);List<UserSocialConnection> findByProviderIdAndProviderUserIdIn(String providerId, Collection<String> providerUserIds);
}

在拥有数据库UserSocialConnectionRepository ,我们将实现Spring Social所需的ConnectionRepositoryUsersConnectionRepository 。 我只是从JdbcConnectionRepositoryJdbcUsersConnectionRepository复制了代码,并创建了自己的MongoConnectionRepositoryMongoUsersConnectionRepository

public class MongoUsersConnectionRepository implements UsersConnectionRepository{private final UserSocialConnectionRepository userSocialConnectionRepository;private final SocialAuthenticationServiceLocator socialAuthenticationServiceLocator;private final TextEncryptor textEncryptor;private ConnectionSignUp connectionSignUp;public MongoUsersConnectionRepository(UserSocialConnectionRepository userSocialConnectionRepository, SocialAuthenticationServiceLocator socialAuthenticationServiceLocator, TextEncryptor textEncryptor){this.userSocialConnectionRepository = userSocialConnectionRepository;this.socialAuthenticationServiceLocator = socialAuthenticationServiceLocator;this.textEncryptor = textEncryptor;}/*** The command to execute to create a new local user profile in the event no user id could be mapped to a connection.* Allows for implicitly creating a user profile from connection data during a provider sign-in attempt.* Defaults to null, indicating explicit sign-up will be required to complete the provider sign-in attempt.* @see #findUserIdsWithConnection(Connection)*/public void setConnectionSignUp(ConnectionSignUp connectionSignUp) {this.connectionSignUp = connectionSignUp;}public List<String> findUserIdsWithConnection(Connection<?> connection) {ConnectionKey key = connection.getKey();List<UserSocialConnection> userSocialConnectionList = this.userSocialConnectionRepository.findByProviderIdAndProviderUserId(key.getProviderId(), key.getProviderUserId());List<String> localUserIds = new ArrayList<String>();for (UserSocialConnection userSocialConnection : userSocialConnectionList){localUserIds.add(userSocialConnection.getUserId());}if (localUserIds.size() == 0 && connectionSignUp != null) {String newUserId = connectionSignUp.execute(connection);if (newUserId != null){createConnectionRepository(newUserId).addConnection(connection);return Arrays.asList(newUserId);}}return localUserIds;}public Set<String> findUserIdsConnectedTo(String providerId, Set<String> providerUserIds) {final Set<String> localUserIds = new HashSet<String>();List<UserSocialConnection> userSocialConnectionList = this.userSocialConnectionRepository.findByProviderIdAndProviderUserIdIn(providerId, providerUserIds);for (UserSocialConnection userSocialConnection : userSocialConnectionList){localUserIds.add(userSocialConnection.getUserId());}return localUserIds;}public ConnectionRepository createConnectionRepository(String userId) {if (userId == null) {throw new IllegalArgumentException('userId cannot be null');}return new MongoConnectionRepository(userId, userSocialConnectionRepository, socialAuthenticationServiceLocator, textEncryptor);}}

MongoUsersConnectionRepository非常类似于JdbcUsersConnectionRepository 。 但是对于MongoConnectionRepository ,我需要进行一些更改:

public class MongoConnectionRepository implements ConnectionRepository {private final String userId;private final UserSocialConnectionRepository userSocialConnectionRepository;private final SocialAuthenticationServiceLocator socialAuthenticationServiceLocator;private final TextEncryptor textEncryptor;public MongoConnectionRepository(String userId, UserSocialConnectionRepository userSocialConnectionRepository,SocialAuthenticationServiceLocator socialAuthenticationServiceLocator, TextEncryptor textEncryptor) {this.userId = userId;this.userSocialConnectionRepository = userSocialConnectionRepository;this.socialAuthenticationServiceLocator = socialAuthenticationServiceLocator;this.textEncryptor = textEncryptor;}public MultiValueMap<String, Connection<?>> findAllConnections() {List<UserSocialConnection> userSocialConnectionList = this.userSocialConnectionRepository.findByUserId(userId);MultiValueMap<String, Connection<?>> connections = new LinkedMultiValueMap<String, Connection<?>>();Set<String> registeredProviderIds = socialAuthenticationServiceLocator.registeredProviderIds();for (String registeredProviderId : registeredProviderIds) {connections.put(registeredProviderId, Collections.<Connection<?>> emptyList());}for (UserSocialConnection userSocialConnection : userSocialConnectionList) {String providerId = userSocialConnection.getProviderId();if (connections.get(providerId).size() == 0) {connections.put(providerId, new LinkedList<Connection<?>>());}connections.add(providerId, buildConnection(userSocialConnection));}return connections;}public List<Connection<?>> findConnections(String providerId) {List<Connection<?>> resultList = new LinkedList<Connection<?>>();List<UserSocialConnection> userSocialConnectionList = this.userSocialConnectionRepository.findByUserIdAndProviderId(userId, providerId);for (UserSocialConnection userSocialConnection : userSocialConnectionList) {resultList.add(buildConnection(userSocialConnection));}return resultList;}@SuppressWarnings('unchecked')public <A> List<Connection<A>> findConnections(Class<A> apiType) {List<?> connections = findConnections(getProviderId(apiType));return (List<Connection<A>>) connections;}public MultiValueMap<String, Connection<?>> findConnectionsToUsers(MultiValueMap<String, String> providerUsers) {if (providerUsers == null || providerUsers.isEmpty()) {throw new IllegalArgumentException('Unable to execute find: no providerUsers provided');}MultiValueMap<String, Connection<?>> connectionsForUsers = new LinkedMultiValueMap<String, Connection<?>>();for (Iterator<Entry<String, List<String>>> it = providerUsers.entrySet().iterator(); it.hasNext();) {Entry<String, List<String>> entry = it.next();String providerId = entry.getKey();List<String> providerUserIds = entry.getValue();List<UserSocialConnection> userSocialConnections = this.userSocialConnectionRepository.findByProviderIdAndProviderUserIdIn(providerId, providerUserIds);List<Connection<?>> connections = new ArrayList<Connection<?>>(providerUserIds.size());for (int i = 0; i < providerUserIds.size(); i++) {connections.add(null);}connectionsForUsers.put(providerId, connections);for (UserSocialConnection userSocialConnection : userSocialConnections) {String providerUserId = userSocialConnection.getProviderUserId();int connectionIndex = providerUserIds.indexOf(providerUserId);connections.set(connectionIndex, buildConnection(userSocialConnection));}}return connectionsForUsers;}public Connection<?> getConnection(ConnectionKey connectionKey) {UserSocialConnection userSocialConnection = this.userSocialConnectionRepository.findByUserIdAndProviderIdAndProviderUserId(userId, connectionKey.getProviderId(),connectionKey.getProviderUserId());if (userSocialConnection != null) {return buildConnection(userSocialConnection);}throw new NoSuchConnectionException(connectionKey);}@SuppressWarnings('unchecked')public <A> Connection<A> getConnection(Class<A> apiType, String providerUserId) {String providerId = getProviderId(apiType);return (Connection<A>) getConnection(new ConnectionKey(providerId, providerUserId));}@SuppressWarnings('unchecked')public <A> Connection<A> getPrimaryConnection(Class<A> apiType) {String providerId = getProviderId(apiType);Connection<A> connection = (Connection<A>) findPrimaryConnection(providerId);if (connection == null) {throw new NotConnectedException(providerId);}return connection;}@SuppressWarnings('unchecked')public <A> Connection<A> findPrimaryConnection(Class<A> apiType) {String providerId = getProviderId(apiType);return (Connection<A>) findPrimaryConnection(providerId);}public void addConnection(Connection<?> connection) {//check cardinalitySocialAuthenticationService<?> socialAuthenticationService = this.socialAuthenticationServiceLocator.getAuthenticationService(connection.getKey().getProviderId());if (socialAuthenticationService.getConnectionCardinality() == ConnectionCardinality.ONE_TO_ONE ||socialAuthenticationService.getConnectionCardinality() == ConnectionCardinality.ONE_TO_MANY){List<UserSocialConnection> storedConnections = this.userSocialConnectionRepository.findByProviderIdAndProviderUserId(connection.getKey().getProviderId(), connection.getKey().getProviderUserId());if (storedConnections.size() > 0){//not allow one providerId connect to multiple userIdthrow new DuplicateConnectionException(connection.getKey());}}UserSocialConnection userSocialConnection = this.userSocialConnectionRepository.findByUserIdAndProviderIdAndProviderUserId(userId, connection.getKey().getProviderId(), connection.getKey().getProviderUserId());if (userSocialConnection == null) {ConnectionData data = connection.createData();userSocialConnection = new UserSocialConnection(userId, data.getProviderId(), data.getProviderUserId(), 0,data.getDisplayName(), data.getProfileUrl(), data.getImageUrl(), encrypt(data.getAccessToken()),encrypt(data.getSecret()), encrypt(data.getRefreshToken()), data.getExpireTime());this.userSocialConnectionRepository.save(userSocialConnection);} else {throw new DuplicateConnectionException(connection.getKey());}}public void updateConnection(Connection<?> connection) {ConnectionData data = connection.createData();UserSocialConnection userSocialConnection = this.userSocialConnectionRepository.findByUserIdAndProviderIdAndProviderUserId(userId, connection.getKey().getProviderId(), connection.getKey().getProviderUserId());if (userSocialConnection != null) {userSocialConnection.setDisplayName(data.getDisplayName());userSocialConnection.setProfileUrl(data.getProfileUrl());userSocialConnection.setImageUrl(data.getImageUrl());userSocialConnection.setAccessToken(encrypt(data.getAccessToken()));userSocialConnection.setSecret(encrypt(data.getSecret()));userSocialConnection.setRefreshToken(encrypt(data.getRefreshToken()));userSocialConnection.setExpireTime(data.getExpireTime());this.userSocialConnectionRepository.save(userSocialConnection);}}public void removeConnections(String providerId) {List<UserSocialConnection> userSocialConnectionList = this.userSocialConnectionRepository.findByUserIdAndProviderId(userId, providerId);for (UserSocialConnection userSocialConnection : userSocialConnectionList) {this.userSocialConnectionRepository.delete(userSocialConnection);}}public void removeConnection(ConnectionKey connectionKey) {UserSocialConnection userSocialConnection = this.userSocialConnectionRepository.findByUserIdAndProviderIdAndProviderUserId(userId, connectionKey.getProviderId(), connectionKey.getProviderUserId());this.userSocialConnectionRepository.delete(userSocialConnection);}// internal helpersprivate Connection<?> buildConnection(UserSocialConnection userSocialConnection) {ConnectionData connectionData = new ConnectionData(userSocialConnection.getProviderId(),userSocialConnection.getProviderUserId(), userSocialConnection.getDisplayName(),userSocialConnection.getProfileUrl(), userSocialConnection.getImageUrl(),decrypt(userSocialConnection.getAccessToken()), decrypt(userSocialConnection.getSecret()),decrypt(userSocialConnection.getRefreshToken()), userSocialConnection.getExpireTime());ConnectionFactory<?> connectionFactory = this.socialAuthenticationServiceLocator.getConnectionFactory(connectionData.getProviderId());return connectionFactory.createConnection(connectionData);}private Connection<?> findPrimaryConnection(String providerId) {List<UserSocialConnection> userSocialConnectionList = this.userSocialConnectionRepository.findByUserIdAndProviderId(userId, providerId);return buildConnection(userSocialConnectionList.get(0));}private <A> String getProviderId(Class<A> apiType) {return socialAuthenticationServiceLocator.getConnectionFactory(apiType).getProviderId();}private String encrypt(String text) {return text != null ? textEncryptor.encrypt(text) : text;}private String decrypt(String encryptedText) {return encryptedText != null ? textEncryptor.decrypt(encryptedText) : encryptedText;}}

首先,我将JdbcTemplate替换为UserSocialConnectionRepository以从数据库中检索UserSocialConnection对象。 然后用spring-social-security模块中的SocialAuthenticationServiceLocator替换ConnectionFactoryLocator 。 最大的变化是addConnection方法(上面已突出显示),它首先检查连接基数。 如果connectionCardinalitysocialAuthenticationServiceONE_TO_ONE (这意味着一个用户id与一个且仅一个对providerId / providerUserId的),或ONE_TO_MANY (这意味着一个用户id可以连接到一个或多个providerId / providerUserId,但一对providerId / providerUserId的只能连接到一个userId)。

完成所有这些自定义之后,最后一步是在spring config中将它们粘合在一起:

@Configuration
public class SocialAndSecurityConfig {@Injectprivate Environment environment;@InjectAccountService accountService;@Injectprivate AuthenticationManager authenticationManager;@Injectprivate UserSocialConnectionRepository userSocialConnectionRepository;@Beanpublic SocialAuthenticationServiceLocator socialAuthenticationServiceLocator() {SocialAuthenticationServiceRegistry registry = new SocialAuthenticationServiceRegistry();//add googleOAuth2ConnectionFactory<Google> googleConnectionFactory = new GoogleConnectionFactory(environment.getProperty('google.clientId'),environment.getProperty('google.clientSecret'));OAuth2AuthenticationService<Google> googleAuthenticationService = new OAuth2AuthenticationService<Google>(googleConnectionFactory);googleAuthenticationService.setScope('https://www.googleapis.com/auth/userinfo.profile');registry.addAuthenticationService(googleAuthenticationService);//add twitterOAuth1ConnectionFactory<Twitter> twitterConnectionFactory = new TwitterConnectionFactory(environment.getProperty('twitter.consumerKey'),environment.getProperty('twitter.consumerSecret'));OAuth1AuthenticationService<Twitter> twitterAuthenticationService = new OAuth1AuthenticationService<Twitter>(twitterConnectionFactory);registry.addAuthenticationService(twitterAuthenticationService);//add facebookOAuth2ConnectionFactory<Facebook> facebookConnectionFactory = new FacebookConnectionFactory(environment.getProperty('facebook.clientId'),environment.getProperty('facebook.clientSecret'));OAuth2AuthenticationService<Facebook> facebookAuthenticationService = new OAuth2AuthenticationService<Facebook>(facebookConnectionFactory);facebookAuthenticationService.setScope('');registry.addAuthenticationService(facebookAuthenticationService);return registry;}/*** Singleton data access object providing access to connections across all users.*/@Beanpublic UsersConnectionRepository usersConnectionRepository() {MongoUsersConnectionRepository repository = new MongoUsersConnectionRepository(userSocialConnectionRepository,socialAuthenticationServiceLocator(), Encryptors.noOpText());repository.setConnectionSignUp(autoConnectionSignUp());return repository;}/*** Request-scoped data access object providing access to the current user's connections.*/@Bean@Scope(value = 'request', proxyMode = ScopedProxyMode.INTERFACES)public ConnectionRepository connectionRepository() {UserAccount user = AccountUtils.getLoginUserAccount();return usersConnectionRepository().createConnectionRepository(user.getUsername());}/*** A proxy to a request-scoped object representing the current user's primary Google account.* * @throws NotConnectedException*             if the user is not connected to Google.*/@Bean@Scope(value = 'request', proxyMode = ScopedProxyMode.INTERFACES)public Google google() {Connection<Google> google = connectionRepository().findPrimaryConnection(Google.class);return google != null ? google.getApi() : new GoogleTemplate();}@Bean@Scope(value='request', proxyMode=ScopedProxyMode.INTERFACES)   public Facebook facebook() {Connection<Facebook> facebook = connectionRepository().findPrimaryConnection(Facebook.class);return facebook != null ? facebook.getApi() : new FacebookTemplate();}@Bean@Scope(value='request', proxyMode=ScopedProxyMode.INTERFACES)   public Twitter twitter() {Connection<Twitter> twitter = connectionRepository().findPrimaryConnection(Twitter.class);return twitter != null ? twitter.getApi() : new TwitterTemplate();}@Beanpublic ConnectionSignUp autoConnectionSignUp() {return new AutoConnectionSignUp(accountService);}@Beanpublic SocialAuthenticationFilter socialAuthenticationFilter() {SocialAuthenticationFilter filter = new SocialAuthenticationFilter(authenticationManager, accountService,usersConnectionRepository(), socialAuthenticationServiceLocator());filter.setFilterProcessesUrl('/signin');filter.setSignupUrl(null); filter.setConnectionAddedRedirectUrl('/myAccount');filter.setPostLoginUrl('/myAccount');return filter;}@Beanpublic SocialAuthenticationProvider socialAuthenticationProvider(){return new SocialAuthenticationProvider(usersConnectionRepository(), accountService);}@Beanpublic LoginUrlAuthenticationEntryPoint socialAuthenticationEntryPoint(){return new LoginUrlAuthenticationEntryPoint('/signin');}}

accountService是我自己的用户帐户服务,用于提供与帐户相关的功能,它实现了SocialUserDetailsServiceUserDetailsServiceUserIdExtractor

还有很多地方需要改进,例如重构MongoConnectionRepositoryMongoUsersConnectionRepository以使用Spring Data Repository接口实现抽象的社交连接存储库实现。 而且我发现有人已经对此提出了一个问题: 利用Spring Data for UsersConnectionRepository 。

参考:来自我们的JCG合作伙伴 Yuan Ji在Jiwhiz博客上为MongoDB定制Spring Social Connect Framework 。

翻译自: https://www.javacodegeeks.com/2013/03/customize-spring-social-connect-framework-for-mongodb.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369237.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跳槽上班第一天的感受

在上家公司呆了快三年&#xff0c;因为想从事与算法相关的工作&#xff0c;跳槽到了另一家公司&#xff0c;今天是上班的第一天&#xff0c;感觉不轻松也不紧张。有意无意的对比了两家公司的工作环境和工作方式&#xff0c;感觉差别是蛮大的&#xff0c;新的工作环境啥的都没有…

以空格为分隔符读取内容给两个变量_问与答61: 如何将一个文本文件中满足指定条件的内容筛选到另一个文本文件中?...

学习Excel技术&#xff0c;关注微信公众号&#xff1a;excelperfectQ&#xff1a;如下图1所示&#xff0c;一个名为“InputFile.csv”文件&#xff0c;每行有6个数字&#xff0c;每个数字使用空格分隔开。图1现在&#xff0c;我要将以60至69开头的行放置到另一个名为“OutputFi…

Chrome调试WebView时Inspect出现空白的解决方法(使用离线包不Fan墙)

起因 使用HTML5开发Android应用时&#xff0c;少不了调试WebView。做前端的还是习惯Chrome的开发者工具&#xff0c;以前都是输入Chrome://inspect就可以调试WebView了&#xff0c;太方便了。 最近老是出现空白页面&#xff0c;各种搜索&#xff0c;最后还是Fan墙解决了。好在…

BZOJ 1008:[HNOI2008]越狱

傻逼题&#xff0c;然后n&#xff0c;m写反了WA了一发。。 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<queue> #include<vector> typedef long long LL; using namespac…

2018年各大互联网前端面试题五(今日头条)

基础 行标签都有哪些&#xff1f;特点&#xff1f;img标签的用法请描述一下cookies&#xff0c;sessionStorage和localStorage的区别&#xff1f;一个div&#xff0c;高度是宽度的50%&#xff0c;让该div的宽度占据整个屏幕&#xff0c;然后能自适应&#xff0c;垂直居中&#…

属性被分为八大类不包括_Python语言---私有属性

属性分为实例属性与类属性方法分为普通方法&#xff0c;类方法&#xff0c;静态方法一&#xff1a;属性&#xff1a;尽量把需要用户传入的属性作为实例属性&#xff0c;而把同类都一样的属性作为类属性。实例属性在每创造一个实例时都会初始化一遍&#xff0c;不同的实例的实例…

CSS 文本溢出时显示省略标记

如标题所示... <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns"http://www.w3.org/1999/xhtml"> <head> <meta http-equiv"Content…

Jenkins分层作业和作业状态汇总

您可能知道&#xff0c;Jenkins是高度可配置的CI服务器。 我们可以设置不同的自定义构建过程。 我将分享一些我用来设置Jenkins工作层次的方法。 这是用例&#xff1a; 我们有一个主入口作业被调用以启动整个构建过程。 这项工作可以有一个到多个子工作。 &#xff08;第2级&…

【Python Programe】WSGI (Web Server Gateway Interface)

Part1: What is a Web server? 一个位于物理服务器上的网络服务器&#xff08;服务器里的服务器&#xff09;&#xff0c;等待客户端去发送request&#xff0c;当服务器接收到request&#xff0c;就会生成一个response发送回客户端&#xff1b; 客户端与服务器使用HTTP协议进…

Redis配置文件配置

Spring和Redis整合&#xff1a; 配置applicationContext-redis.xml&#xff0c;添加Redis服务&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:context"ht…

华大单片机m4内核的滴答定时器_微处理器、单片机及其外设,处理还是控制?...

每项新应用设计都需要一个单片机或微处理器。当在两者之间选择其一时&#xff0c;需要考虑一些因素。以下是微处理器、单片机以及异构架构的概述。考虑选择微处理器(MPU)或者单片机(MCU)时&#xff0c;应用类型通常是关键因素。另一方面&#xff0c;最终选择取决于诸如操作系统…

option标签selected=selected属性失效的问题

要在select标签上面加上autocomplete"off"关闭自动完成&#xff0c;不然浏览器每次刷新后将自动选择上一次关闭时的option&#xff0c;这样默认属性selected"selected"就会失效啦 要记住每次遇到select标签时就最好要加上autocomplete"off"这一项…

Spring集成–从头开始应用程序,第2部分

这是本教程的第二部分&#xff0c;我们将使用Spring Integration创建发票处理应用程序。 如果您错过了它&#xff0c;一定要看一下第一部分 。 以前&#xff0c;我们已经定义了系统的功能要求&#xff0c;创建了网关&#xff0c;分离器&#xff0c;过滤器和路由器组件。 让我们…

H5添加禁止缩放功能

<meta name"viewport" content"widthdevice-width, initial-scale1.0, maximum-scale1.0, minimum-scale1.0, user-scalableno, target-densitydpidevice-dpi" />

安装提示卸载office_office2010 卸载工具

点击上方“蓝字”&#xff0c;关注我们获取更多免费资源我们为什么要用这个office2010卸载工具呢&#xff0c;很简单旧版本的office卸载不干净&#xff0c;在安装新版本的office时可能会遇到一些奇奇怪怪的问题。如果遇到无法安装office时&#xff0c;我们可以先使用office卸载…

C++primer 15.6节练习

练习15.23 1 class Base {2 public:3 virtual int fcn();4 };5 6 class D1 : public Base {7 public:8 int fcn();9 virtual void f2(); 10 }; 11 12 class D2 : public D1 { 13 public: 14 int fcn(int); 15 int fcn(); 16 void f2(); 17 }; 18 跟bp…

Java中Comparator和Comparable之间的区别

常见的面试问题之一是“比较器和可比较器之间有什么区别”。 或“您将如何通过其ID或名称对员工对象集合进行排序”。为此&#xff0c;我们可以使用两个接口&#xff0c;即Comparator和Comparable。在我们真正看到差异之前&#xff0c;让我简要介绍一下两者。 可比接口&#x…

bzoj2375 疯狂的涂色

疯狂的涂色 Time Limit: 5 Sec Memory Limit: 128 MB Description 小t非常喜爱画画&#xff0c;但是他还是一个初学者。他最近费尽千辛万苦才拜到已仙逝的达芬奇为师&#xff08;神仙&#xff1f;妖怪&#xff1f;谢谢&#xff09;。达芬奇果然是画鸡蛋长大的&#xff0c;让小t…

人工通道会取消吗_二七政策将用于ETC?高速或将取消人工收费通道

随着社会的发展&#xff0c;有车一族越来越多&#xff0c;但是在这种情况下&#xff0c;堵车的情况就随处可见了&#xff0c;并且随着车辆的增多&#xff0c;高速收费通道的成本也增加了不少&#xff0c;而且通过时间越来越长&#xff0c;面对这种情况&#xff0c;交通局就和银…

零基础的前端开发初学者应如何系统地学习?

网站开发开发大致分为前端和后端&#xff0c;前端主要负责实现视觉和交互效果&#xff0c;以及与服务器通信&#xff0c;完成业务逻辑。其核心价值在于对用户体验的追求。可以按如下思路学习系统学习&#xff1a; 基础知识&#xff1a; html css 这部分建议在 w3school 在线教…