package com.wangsaichao.cas.controller;
import org.apereo.cas.services.*;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.net.URL;
/**
* @author: wangsaichao
* @date: 2018/8/10
* @description:
*/
@RestController
public class ServiceController {
private Logger logger = LoggerFactory.getLogger(ServiceController.class);
@Autowired
@Qualifier("servicesManager")
private ServicesManager servicesManager;
/**
* 注册service
* @param serviceId 域名
* @param id 顺序
* @return
*/
@RequestMapping(value = "/addClient/{serviceId}/{id}",method = RequestMethod.GET)
public Object addClient(@PathVariable("serviceId") String serviceId, @PathVariable("id") int id) {
try {
String a="^(https|imaps|http)://"+serviceId+".*";
RegexRegisteredService service = new RegexRegisteredService();
ReturnAllAttributeReleasePolicy re = new ReturnAllAttributeReleasePolicy();
service.setServiceId(a);
service.setId(id);
service.setAttributeReleasePolicy(re);
service.setName("login");
//这个是为了单点登出而作用的
service.setLogoutUrl(new URL("http://"+serviceId));
servicesManager.save(service);
//执行load让他生效
servicesManager.load();
ReturnMessage returnMessage = new ReturnMessage();
returnMessage.setCode(200);
returnMessage.setMessage("添加成功");
return returnMessage;
} catch (Exception e) {
logger.error("注册service异常",e);
ReturnMessage returnMessage = new ReturnMessage();
returnMessage.setCode(500);
returnMessage.setMessage("添加失败");
return returnMessage;
}
}
/**
* 删除service异常
* @param serviceId
* @return
*/
@RequestMapping(value = "/deleteClient/{serviceId}/{id}",method = RequestMethod.GET)
public Object deleteClient(@PathVariable("serviceId") String serviceId,@PathVariable("id") int id) {
try {
// String a="^(https|imaps|http)://"+serviceId+".*";
// String a="^(https|imaps|http)://"+serviceId+".*";
// RegexRegisteredService service = new RegexRegisteredService();
// ReturnAllAttributeReleasePolicy re = new ReturnAllAttributeReleasePolicy();
// service.setServiceId(a);
// service.setId(id);
// service.setAttributeReleasePolicy(re);
// service.setName("login");
// //这个是为了单点登出而作用的
// service.setLogoutUrl(new URL("http://"+serviceId));
String aa = "http://app2.cas.com:8082";
RegisteredService service = servicesManager.findServiceBy(aa);
servicesManager.delete(service);
//执行load生效
servicesManager.load();
ReturnMessage returnMessage = new ReturnMessage();
returnMessage.setCode(200);
returnMessage.setMessage("删除成功");
return returnMessage;
} catch (Exception e) {
logger.error("删除service异常",e);
ReturnMessage returnMessage = new ReturnMessage();
returnMessage.setCode(500);
returnMessage.setMessage("删除失败");
return returnMessage;
}
}
public class ReturnMessage{
private Integer code;
private String message;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
}
增加http接口,操作数据库添加或删除service
这里为了方便直接在地址栏操作增加或删除。代码如下:
package com.wangsaichao.cas.controller;
import org.apereo.cas.services.*;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.net.URL;
/**
* @author: wangsaichao
* @date: 2018/8/10
* @description:
*/
@RestController
public class ServiceController {
private Logger logger = LoggerFactory.getLogger(ServiceController.class);
@Autowired
@Qualifier("servicesManager")
private ServicesManager servicesManager;
/**
* 注册service
* @param serviceId 域名
* @param id 顺序
* @return
*/
@RequestMapping(value = "/addClient/{serviceId}/{id}",method = RequestMethod.GET)
public Object addClient(@PathVariable("serviceId") String serviceId, @PathVariable("id") int id) {
try {
String a="^(https|imaps|http)://"+serviceId+".*";
RegexRegisteredService service = new RegexRegisteredService();
ReturnAllAttributeReleasePolicy re = new ReturnAllAttributeReleasePolicy();
service.setServiceId(a);
service.setId(id);
service.setAttributeReleasePolicy(re);
service.setName("login");
//这个是为了单点登出而作用的
service.setLogoutUrl(new URL("http://"+serviceId));
servicesManager.save(service);
//执行load让他生效
servicesManager.load();
ReturnMessage returnMessage = new ReturnMessage();
returnMessage.setCode(200);
returnMessage.setMessage("添加成功");
return returnMessage;
} catch (Exception e) {
logger.error("注册service异常",e);
ReturnMessage returnMessage = new ReturnMessage();
returnMessage.setCode(500);
returnMessage.setMessage("添加失败");
return returnMessage;
}
}
/**
* 删除service异常
* @param serviceId
* @return
*/
@RequestMapping(value = "/deleteClient/{serviceId}/{id}",method = RequestMethod.GET)
public Object deleteClient(@PathVariable("serviceId") String serviceId,@PathVariable("id") int id) {
try {
// String a="^(https|imaps|http)://"+serviceId+".*";
// String a="^(https|imaps|http)://"+serviceId+".*";
// RegexRegisteredService service = new RegexRegisteredService();
// ReturnAllAttributeReleasePolicy re = new ReturnAllAttributeReleasePolicy();
// service.setServiceId(a);
// service.setId(id);
// service.setAttributeReleasePolicy(re);
// service.setName("login");
// //这个是为了单点登出而作用的
// service.setLogoutUrl(new URL("http://"+serviceId));
String aa = "http://app2.cas.com:8082";
RegisteredService service = servicesManager.findServiceBy(aa);
servicesManager.delete(service);
//执行load生效
servicesManager.load();
ReturnMessage returnMessage = new ReturnMessage();
returnMessage.setCode(200);
returnMessage.setMessage("删除成功");
return returnMessage;
} catch (Exception e) {
logger.error("删除service异常",e);
ReturnMessage returnMessage = new ReturnMessage();
returnMessage.setCode(500);
returnMessage.setMessage("删除失败");
return returnMessage;
}
}
public class ReturnMessage{
private Integer code;
private String message;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
启动服务
1.启动服务报错
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘type=MyISAM’ at line 5 原因是上面的配置:cas.serviceRegistry.dialect=org.hibernate.dialect.MySQLDialect 应该改为: cas.serviceRegistry.dialect=org.hibernate.dialect.MySQL5Dialect
在添加service的时候没问题,但是在删除service的时候报以下异常: java.lang.IllegalArgumentException: ‘actionPerformed’ cannot be null. Check the correctness of @Audit annotation at the following audit point: execution(public synchronized org.apereo.cas.services.RegisteredService 经过debug发现,代码其实是没问题的,可以正常删除,但是在执行AuditTrailManagementAspect类中下面这段代码的时候报异常: 我们发现auditActionResolver和auditResourceResolver是null,经过搜索,找到了下面这篇文章,在此感谢作者,博客地址: https://www.qyh.me/space/java/article/cas-sso-different-application
package org.apereo.cas.audit.spi.config;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.audit.*;
import org.apereo.cas.audit.spi.*;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.model.core.audit.AuditProperties;
import org.apereo.cas.configuration.model.core.audit.AuditSlf4jLogProperties;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.inspektr.audit.AuditTrailManagementAspect;
import org.apereo.inspektr.audit.spi.AuditActionResolver;
import org.apereo.inspektr.audit.spi.AuditResourceResolver;
import org.apereo.inspektr.audit.spi.support.DefaultAuditActionResolver;
import org.apereo.inspektr.audit.support.Slf4jLoggingAuditTrailManager;
import org.apereo.inspektr.common.spi.PrincipalResolver;
import org.apereo.inspektr.common.web.ClientInfoThreadLocalFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This is {@link CasCoreAuditConfiguration}.
*
* @author Misagh Moayyed
* @since 5.0.0
*/
@Configuration("casCoreAuditConfiguration")
@EnableAspectJAutoProxy
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CasCoreAuditConfiguration implements AuditTrailExecutionPlanConfigurer, AuditTrailRecordResolutionPlanConfigurer {
private static final Logger LOGGER = LoggerFactory.getLogger(CasCoreAuditConfiguration.class);
private static final String AUDIT_ACTION_SUFFIX_FAILED = "_FAILED";
@Autowired
private CasConfigurationProperties casProperties;
@Autowired
private ApplicationContext applicationContext;
@Bean
public AuditTrailManagementAspect auditTrailManagementAspect(@Qualifier("auditTrailExecutionPlan") final AuditTrailExecutionPlan auditTrailExecutionPlan,
@Qualifier("auditTrailRecordResolutionPlan") final AuditTrailRecordResolutionPlan auditTrailRecordResolutionPlan) {
final AuditTrailManagementAspect aspect = new AuditTrailManagementAspect(
casProperties.getAudit().getAppCode(),
auditablePrincipalResolver(auditPrincipalIdProvider()),
auditTrailExecutionPlan.getAuditTrailManagers(), auditTrailRecordResolutionPlan.getAuditActionResolvers(),
auditTrailRecordResolutionPlan.getAuditResourceResolvers());
aspect.setFailOnAuditFailures(!casProperties.getAudit().isIgnoreAuditFailures());
return aspect;
}
@Autowired
@ConditionalOnMissingBean(name = "auditTrailRecordResolutionPlan")
@Bean
public AuditTrailRecordResolutionPlan auditTrailRecordResolutionPlan(final List configurers) {
final DefaultAuditTrailRecordResolutionPlan plan = new DefaultAuditTrailRecordResolutionPlan();
configurers.forEach(c -> {
final String name = StringUtils.removePattern(c.getClass().getSimpleName(), "\\$.+");
LOGGER.debug("Registering audit trail manager [{}]", name);
c.configureAuditTrailRecordResolutionPlan(plan);
});
return plan;
}
@Autowired
@ConditionalOnMissingBean(name = "auditTrailExecutionPlan")
@Bean
public AuditTrailExecutionPlan auditTrailExecutionPlan(final List configurers) {
final DefaultAuditTrailExecutionPlan plan = new DefaultAuditTrailExecutionPlan();
configurers.forEach(c -> {
final String name = StringUtils.removePattern(c.getClass().getSimpleName(), "\\$.+");
LOGGER.debug("Registering audit trail manager [{}]", name);
c.configureAuditTrailExecutionPlan(plan);
});
return plan;
}
@Bean
public FilterRegistrationBean casClientInfoLoggingFilter() {
final AuditProperties audit = casProperties.getAudit();
final FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new ClientInfoThreadLocalFilter());
bean.setUrlPatterns(CollectionUtils.wrap("/*"));
bean.setName("CAS Client Info Logging Filter");
bean.setAsyncSupported(true);
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
final Map initParams = new HashMap<>();
if (StringUtils.isNotBlank(audit.getAlternateClientAddrHeaderName())) {
initParams.put(ClientInfoThreadLocalFilter.CONST_IP_ADDRESS_HEADER, audit.getAlternateClientAddrHeaderName());
}
if (StringUtils.isNotBlank(audit.getAlternateServerAddrHeaderName())) {
initParams.put(ClientInfoThreadLocalFilter.CONST_SERVER_IP_ADDRESS_HEADER, audit.getAlternateServerAddrHeaderName());
}
initParams.put(ClientInfoThreadLocalFilter.CONST_USE_SERVER_HOST_ADDRESS, String.valueOf(audit.isUseServerHostAddress()));
bean.setInitParameters(initParams);
return bean;
}
@ConditionalOnMissingBean(name = "deleteServiceActionResolver")
@Bean
public AuditActionResolver deleteServiceActionResolver() {
return new DeleteServiceActionResolver();
}
@ConditionalOnMissingBean(name = "deleteServiceResourceResolver")
@Bean
public AuditResourceResolver deleteServiceResourceResolver() {
return new DeleteServiceResourceResolver();
}
@ConditionalOnMissingBean(name = "authenticationActionResolver")
@Bean
public AuditActionResolver authenticationActionResolver() {
return new DefaultAuditActionResolver("_SUCCESS", AUDIT_ACTION_SUFFIX_FAILED);
}
@ConditionalOnMissingBean(name = "ticketCreationActionResolver")
@Bean
public AuditActionResolver ticketCreationActionResolver() {
return new DefaultAuditActionResolver("_CREATED", "_NOT_CREATED");
}
@ConditionalOnMissingBean(name = "ticketValidationActionResolver")
@Bean
public AuditActionResolver ticketValidationActionResolver() {
return new DefaultAuditActionResolver("D", AUDIT_ACTION_SUFFIX_FAILED);
}
@ConditionalOnMissingBean(name = "returnValueResourceResolver")
@Bean
public AuditResourceResolver returnValueResourceResolver() {
return new ShortenedReturnValueAsStringResourceResolver();
}
@ConditionalOnMissingBean(name = "nullableReturnValueResourceResolver")
@Bean
public AuditResourceResolver nullableReturnValueResourceResolver() {
return new NullableReturnValueAuditResourceResolver(returnValueResourceResolver());
}
@ConditionalOnMissingBean(name = "serviceAccessEnforcementAuditResourceResolver")
@Bean
public ServiceAccessEnforcementAuditResourceResolver serviceAccessEnforcementAuditResourceResolver() {
return new ServiceAccessEnforcementAuditResourceResolver();
}
/**
* Extension point for deployers to define custom AuditActionResolvers to extend the stock resolvers.
*
* @return the map
*/
@ConditionalOnMissingBean(name = "customAuditActionResolverMap")
@Bean
public Map customAuditActionResolverMap() {
return new HashMap<>(0);
}
/**
* Extension point for deployers to define custom AuditResourceResolvers to extend the stock resolvers.
*
* @return the map
*/
@ConditionalOnMissingBean(name = "customAuditResourceResolverMap")
@Bean
public Map customAuditResourceResolverMap() {
return new HashMap<>(0);
}
@ConditionalOnMissingBean(name = "auditablePrincipalResolver")
@Bean
public PrincipalResolver auditablePrincipalResolver(@Qualifier("auditPrincipalIdProvider") final AuditPrincipalIdProvider auditPrincipalIdProvider) {
return new ThreadLocalPrincipalResolver(auditPrincipalIdProvider);
}
@ConditionalOnMissingBean(name = "ticketResourceResolver")
@Bean
public AuditResourceResolver ticketResourceResolver() {
return new TicketAsFirstParameterResourceResolver();
}
@ConditionalOnMissingBean(name = "ticketValidationResourceResolver")
@Bean
public AuditResourceResolver ticketValidationResourceResolver() {
final AuditProperties audit = casProperties.getAudit();
if (audit.isIncludeValidationAssertion()) {
return new TicketValidationResourceResolver();
}
return ticketResourceResolver();
}
@ConditionalOnMissingBean(name = "messageBundleAwareResourceResolver")
@Bean
public AuditResourceResolver messageBundleAwareResourceResolver() {
return new MessageBundleAwareResourceResolver(applicationContext);
}
@ConditionalOnMissingBean(name = "auditPrincipalIdProvider")
@Bean
public AuditPrincipalIdProvider auditPrincipalIdProvider() {
final Map resolvers = applicationContext.getBeansOfType(AuditPrincipalIdProvider.class, false, true);
final List providers = new ArrayList<>(resolvers.values());
AnnotationAwareOrderComparator.sort(providers);
return new ChainingAuditPrincipalIdProvider(providers);
}
@Override
public void configureAuditTrailExecutionPlan(final AuditTrailExecutionPlan plan) {
final AuditSlf4jLogProperties audit = casProperties.getAudit().getSlf4j();
final Slf4jLoggingAuditTrailManager slf4j = new Slf4jLoggingAuditTrailManager();
slf4j.setUseSingleLine(audit.isUseSingleLine());
slf4j.setEntrySeparator(audit.getSinglelineSeparator());
slf4j.setAuditFormat(audit.getAuditFormat());
plan.registerAuditTrailManager(slf4j);
}
@Override
public void configureAuditTrailRecordResolutionPlan(final AuditTrailRecordResolutionPlan plan) {
final AuditActionResolver deleteServiceActionResolver = deleteServiceActionResolver();
plan.registerAuditActionResolver("DELETE_SERVICE_ACTION_RESOLVER",deleteServiceActionResolver);
final AuditResourceResolver deleteServiceResourceResolver = deleteServiceResourceResolver();
plan.registerAuditResourceResolver("DELETE_SERVICE_RESOURCE_RESOLVER",deleteServiceResourceResolver);
/*
Add audit action resolvers here.
*/
final AuditActionResolver resolver = authenticationActionResolver();
plan.registerAuditActionResolver("AUTHENTICATION_RESOLVER", resolver);
plan.registerAuditActionResolver("SAVE_SERVICE_ACTION_RESOLVER", resolver);
final AuditActionResolver defResolver = new DefaultAuditActionResolver();
plan.registerAuditActionResolver("DESTROY_TICKET_GRANTING_TICKET_RESOLVER", defResolver);
plan.registerAuditActionResolver("DESTROY_PROXY_GRANTING_TICKET_RESOLVER", defResolver);
final AuditActionResolver cResolver = ticketCreationActionResolver();
plan.registerAuditActionResolver("CREATE_PROXY_GRANTING_TICKET_RESOLVER", cResolver);
plan.registerAuditActionResolver("GRANT_SERVICE_TICKET_RESOLVER", cResolver);
plan.registerAuditActionResolver("GRANT_PROXY_TICKET_RESOLVER", cResolver);
plan.registerAuditActionResolver("CREATE_TICKET_GRANTING_TICKET_RESOLVER", cResolver);
final AuditActionResolver authResolver = new DefaultAuditActionResolver("_TRIGGERED", StringUtils.EMPTY);
plan.registerAuditActionResolver("AUTHENTICATION_EVENT_ACTION_RESOLVER", authResolver);
plan.registerAuditActionResolver("VALIDATE_SERVICE_TICKET_RESOLVER", ticketValidationActionResolver());
final AuditActionResolver serviceAccessResolver = new DefaultAuditActionResolver("_TRIGGERED", StringUtils.EMPTY);
plan.registerAuditActionResolver("SERVICE_ACCESS_ENFORCEMENT_ACTION_RESOLVER", serviceAccessResolver);
/*
Add audit resource resolvers here.
*/
plan.registerAuditResourceResolver("AUTHENTICATION_RESOURCE_RESOLVER", new CredentialsAsFirstParameterResourceResolver());
final AuditResourceResolver messageBundleAwareResourceResolver = messageBundleAwareResourceResolver();
plan.registerAuditResourceResolver("CREATE_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER", messageBundleAwareResourceResolver);
plan.registerAuditResourceResolver("CREATE_PROXY_GRANTING_TICKET_RESOURCE_RESOLVER", messageBundleAwareResourceResolver);
final AuditResourceResolver ticketResourceResolver = ticketResourceResolver();
plan.registerAuditResourceResolver("DESTROY_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER", ticketResourceResolver);
plan.registerAuditResourceResolver("DESTROY_PROXY_GRANTING_TICKET_RESOURCE_RESOLVER", ticketResourceResolver);
plan.registerAuditResourceResolver("GRANT_SERVICE_TICKET_RESOURCE_RESOLVER", new ServiceResourceResolver());
plan.registerAuditResourceResolver("GRANT_PROXY_TICKET_RESOURCE_RESOLVER", new ServiceResourceResolver());
plan.registerAuditResourceResolver("VALIDATE_SERVICE_TICKET_RESOURCE_RESOLVER", ticketValidationResourceResolver());
plan.registerAuditResourceResolver("SAVE_SERVICE_RESOURCE_RESOLVER", returnValueResourceResolver());
plan.registerAuditResourceResolver("AUTHENTICATION_EVENT_RESOURCE_RESOLVER", nullableReturnValueResourceResolver());
plan.registerAuditResourceResolver("SERVICE_ACCESS_ENFORCEMENT_RESOURCE_RESOLVER", serviceAccessEnforcementAuditResourceResolver());
/*
Add custom resolvers here.
*/
plan.registerAuditActionResolvers(customAuditActionResolverMap());
plan.registerAuditResourceResolvers(customAuditResourceResolverMap());
}
}
DeleteServiceActionResolver.java
package org.apereo.cas.audit.spi.config;
import org.apereo.inspektr.audit.annotation.Audit;
import org.apereo.inspektr.audit.spi.support.AbstractSuffixAwareAuditActionResolver;
import org.aspectj.lang.JoinPoint;
/**
* @author: wangsaichao
* @date: 2018/8/10
* @description:
*/
public class DeleteServiceActionResolver extends AbstractSuffixAwareAuditActionResolver {
/**
* Constructs the resolver with empty values for the two suffixes.
*/
public DeleteServiceActionResolver() {
this("","");
}
/**
* Constructs the {@link DeleteServiceActionResolver} with a success suffix and failure
* suffix. CANNOT be NULL.
* @param successSuffix the suffix to use in the event of a success.
* @param failureSuffix the suffix to use in the event of a failure.
*/
public DeleteServiceActionResolver(final String successSuffix, final String failureSuffix) {
super(successSuffix, failureSuffix);
}
@Override
public String resolveFrom(final JoinPoint auditableTarget, final Object retval, final Audit audit) {
return audit.action() + getSuccessSuffix();
}
@Override
public String resolveFrom(final JoinPoint auditableTarget, final Exception exception, final Audit audit) {
return audit.action() + getFailureSuffix();
}
}
DeleteServiceResourceResolver.java
package org.apereo.cas.audit.spi.config;
import org.apereo.inspektr.audit.spi.AuditResourceResolver;
import org.aspectj.lang.JoinPoint;
/**
* @author: wangsaichao
* @date: 2018/8/10
* @description:
*/
public class DeleteServiceResourceResolver implements AuditResourceResolver {
@Override
public String[] resolveFrom(JoinPoint target, Object returnValue) {
return new String[0];
}
@Override
public String[] resolveFrom(JoinPoint target, Exception exception) {
return new String[0];
}
}
public class Server
{
//用来存储所有连接上来的客户
private List<ServerThread> clients;
public static void main(String[] args)
{
Server s = new Server();
s.startServer(9988);
}
publi
I got serveral questions about auto.offset.reset. This configuration parameter governs how consumer read the message from Kafka when there is no initial offset in ZooKeeper or
two cursors.
Make the first cursor go K steps first.
/*
* 第 13 题:题目:输入一个单向链表,输出该链表中倒数第 k 个节点
*/
public void displayKthItemsBackWard(ListNode head,int k){
ListNode p1=head,p2=head;
一、sh 脚本不执行的原因
sh脚本不执行的原因 只有2个
1.权限不够
2.sh脚本里路径没写完整。
二、解决You have new mail in /var/spool/mail/root
修改/usr/share/logwatch/default.conf/logwatch.conf配置文件
MailTo =
MailFrom
三、查询连接数
$ git push joe prod-2295-1
To [email protected]:joe.le/dr-frontend.git
! [rejected] prod-2295-1 -> prod-2295-1 (non-fast-forward)
error: failed to push some refs to '[email protected]