GVKun编程网logo

两种方式实现Spring 业务验证(spring数据验证)

14

对于想了解两种方式实现Spring业务验证的读者,本文将是一篇不可错过的文章,我们将详细介绍spring数据验证,并且为您提供关于5.3Spring5源码--SpringAOP使用接口方式实现、Ide

对于想了解两种方式实现Spring 业务验证的读者,本文将是一篇不可错过的文章,我们将详细介绍spring数据验证,并且为您提供关于5.3 Spring5源码--Spring AOP使用接口方式实现、Idea环境实现SpringBoot实现两种热部署方式(亲测有效)、Intellij IDEA实现SpringBoot项目多端口启动的两种方法、Java中5种方式实现String反转的有价值信息。

本文目录一览:

两种方式实现Spring 业务验证(spring数据验证)

两种方式实现Spring 业务验证(spring数据验证)


关注公众号回复002,有你想要的一切



这是 cxuan 的第 33 篇原创文章

验证在任何时候都非常关键。考虑将数据验证作为业务逻辑开发有利也有弊,Spring 认为,验证不应该只在Web 端进行处理,在服务端也要进行相应的处理,可以防止脏数据存入数据库中,从而避免为运维同学和测试同学造成更大的困扰,因为数据造成的bug会更加难以发现,而且开发人员关注点也不会放在数据本身的问题上,所以做服务端的验证也是非常有必要的。考虑到上面这些问题,Spring 提供了两种主要类型的验证:

  • 一个是实现Validator 接口来创建自定义验证器,用于服务端数据校验。

  • 一种是通过Spring 对Bean Validation 支持实现的。

通过使用 Spring Validator 接口进行验证

Spring 提供 Validator 接口用于验证对象。Validator 接口通过使用 Errors 对象来工作,以便在验证时,验证器可以向 Errors 对象报告验证失败。下面是一个简单的 对象示例

public class Person {

private String name;
private int age;

// get and set...
}

下面一个例子为 Person 对象提供了一种验证方式,通过实现了 org.springframework.validation.Validator 接口 的两个方法:

  • supports(Class): 表示此 Validator 是否能够验证提供的类的实例

  • validate(Object, org.springframework.validation.Errors): 验证给定的对象,如果验证错误,则注册具有给定 Errors 对象。

实现一个 Validator 非常简单,而且Spring 也提供了 ValidationUtils 工具类帮助进行验证。下面是一个验证 Person 对象的例子:

@Component
public class PersonValidator implements Validator {

// 此 Validator 只验证 Person 实例
public boolean supports(Class clazz) {
return Person.class.equals(clazz);
}

public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
}
}

上面代码示例中的静态方法 rejectIfEmpty() 方法用于拒绝name属性,当name 属性是 null 或者是 空串的时候。查看 ValidationUtils 文档关于它能够提供的功能。

然后再来编写配置类 AppConfig:

@Configuration
@ComponentScan("com.spring.validation")
public class AppConfig {}

使用 @Configuration 注解声明此类为配置类(更多 @Configuration 的用法,请参照 原创 | 我被面试官给虐懵了,竟然是因为我不懂Spring中的@Configuration )

配置@ComponentScan 注解用于自动装配,默认是使用 basePackages 扫描指定包,字符串表示。

然后对上面的程序进行验证

public class SpringValidationApplicationTests {

public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

Person person = new Person();
person.setAge(18);
person.setName(null);

PersonValidator personValidator = applicationContext.getBean("personValidator", PersonValidator.class);
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person,"cxuan");

ValidationUtils.invokeValidator(personValidator,person,result);

List<ObjectError> allErrors = result.getAllErrors();
allErrors.forEach(e-> System.out.println(e.getCode()));
}
}

因为是基于注解的配置,所以使用 AnnotationConfigApplicationContext上下文启动类,把配置类 AppConfig 当作参数,然后构建一个Person 类,为了测试验证有效性,把 name 设置为 null,然后通过上下问的 getBean 方法获得 personValidator 的实例,通过使用 BeanPropertyBindingResult 把 person 绑定为 cxuan 的名字,然后使用 ValidationUtils 工具类进行验证,最后把验证的结果进行检查。

上面程序经验证后的结果如下:

org.springframework.validation.ValidationUtils - Invoking validator [com.spring.validation.PersonValidator@37918c79] DEBUG org.springframework.validation.ValidationUtils - Validator found 1 errors name.empty

使用 Bean Validation 进行验证

从 Spring4 开始,就已经实现对 JSR-349 Bean Validation 的全面支持。Bean Validation API 在 javax.validation.constraints 包中以 Java 注解(例如 @NonNull) 形式定义了一组可用域对象的约束。

通过使用 Bean Validation API ,可以避免耦合到特定的验证服务提供程序。Spring 对 Bean Validation API 提供了无缝支持,主要使用一些注解进行验证,下面一起来看一下

定义对象属性上的验证约束

首先,将验证约束应用于域对象属性。使用maven 配置需要引入对应的依赖

<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>

之后定义了一些实体类,使用 javax.validation.constraints 包中的注释进行标注

public class Singer {

@NotNull
@Size(min = 2,max = 60)
private String firstName;

private String lastName;

@NotNull
private Genre genre;

private Gender gender;

get and set...
}

对于 firstName ,定义了两个约束,第一个约束由 @NotNull 进行控制,它表示该值不能为空。此外,@Size注解控制着 firstName 的长度在 2 - 60 之间。@NotNull 还用于 genre 属性。下面是GenreGender 的枚举类

public enum Genre {

POP("P"),
JAZZ("J"),
BLUES("B"),
COUNTRY("C");

private String code;

private Genre(String code){
this.code = code;
}

public String toString(){
return this.code;
}
}

public enum Gender {

MALE("M"),
FEMALE("F");

private String code;

Gender(String code){
this.code = code;
}

@Override
public String toString() {
return this.code;
}
}

Genre 表示歌手所属的音乐类型,而 Gender 与音乐事业不相关,所以可以为空

在 Spring 中配置 Bean Validation 支持

为了在 Spring 的 ApplicationContext 中配置对 Bean Validation API 的支持,可以在Spring 的配置中定义一个 LocalValidatorFactoryBean 的 bean如下

@Configuration
@ComponentScan("com.spring.validation")
public class ValidationConfig {

@Bean
LocalValidatorFactoryBean validatorFactoryBean(){
return new LocalValidatorFactoryBean();
}
}

声明一个 LocalValidatorFactoryBean 的 bean 是必须的。默认情况下,Spring 会在类路径下搜索 Hibernate Validator库,验证它是否存在。

下面我们编写一个为 Singer 类提供验证服务的服务类

@Service
public class SingerValidationService {

@Autowired
private Validator validator;

public Set<ConstraintViolation<Singer>> validateSinger(Singer singer){
return validator.validate(singer);
}
}

注入一个 javax.validation.Validator 实例(请注意与 Spring 提供的 Validator 接口不同)。一旦定义了 LocalValidatorFactoryBean ,就可以在应用程序中的任意位置创建 Validator 的句柄。要在 POJO 上进行验证,需要调用 validator.validate 方法,验证结果以 ConstraintViolation<T> 接口的集合形式返回。下面是上面例子程序的验证

public class SpringBeanValidationTest {

public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ValidationConfig.class);

SingerValidationService singerBean = applicationContext.getBean(SingerValidationService.class);

Singer singer = new Singer();
singer.setFirstName("c");
singer.setLastName("xuan");
singer.setGenre(null);
singer.setGender(null);

validateSinger(singer,singerBean);

applicationContext.close();
}

private static void validateSinger(Singer singer,SingerValidationService singerValidationService){
Set<ConstraintViolation<Singer>> violationSet = singerValidationService.validateSinger(singer);
listViolations(violationSet);
}

private static void listViolations(Set<ConstraintViolation<Singer>> violations){
System.out.println("violations.size() = " + violations.size());
for(ConstraintViolation<Singer> violation : violations){
System.out.println("Validation error for property : " + violation.getPropertyPath());
System.out.println("with value : " + violation.getInvalidValue());
System.out.println("with error message : " + violation.getMessage());
}
}
}

上述代码构建了一个 Singer 类进行验证,因为 firstname 属性的要求是长度介于 2 - 60 之间并且不能为null,所以这里只用了一个字符验证,genre 属性不能为null,最核心的验证方法就是 singerValidationService.validateSinger(singer).方法,它会调用

public Set<ConstraintViolation<Singer>> validateSinger(Singer singer){
return validator.validate(singer);
}

进行验证,验证的结果返回的是 ConstraintViolation<Singler>类型,然后把对应的错误信息输出,上面的错误信息是

violations.size() = 2 Validation error for property : firstName with value : c with error message : 个数必须在2和60之间 Validation error for property : genre with value : null with error message : 不能为null

可以打印出两个错误,并输出错误的属性、值以及错误信息。


你点的每个好看,我都认真当成了喜欢



本文分享自微信公众号 - Java建设者(javajianshe)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

5.3 Spring5源码--Spring AOP使用接口方式实现

5.3 Spring5源码--Spring AOP使用接口方式实现

Spring 提供了很多的实现AOP的方式:Spring 接口方式,schema配置方式和注解.

本文重点介绍Spring使用接口方式实现AOP. 研究使用接口方式实现AOP,以了解为目的. 更好地理解spring使用动态代理实现AOP. 通常我们使用的更多的是使用注解的方式实现AOP

下面来看看如何实现接口方式的AOP

一. 环境准备

要在项目中使用Spring AOP 则需要在项目中导入除了spring jar包之外,还需要引入aspectjrt.jar,aspectjweaver.jar,aopalliance.jar ,spring-aop-3.2.0.M2.jar和cglib.jar 

二、Spring接口方式实现AOP步骤

使用Spring aop接口方式实现aop,可以通过自定义通知来供Spring AOP识别. 常见的自己定义通知有:前置通知,后置通知,返回通知,异常通知,环绕通知. 对应实现的接口是:

  • 前置通知: MethodBeforeAdvice
  • 后置通知: Afteradvice
  • 返回通知:AfterReturningAdvice
  • 异常通知:ThrowsAdvice
  • 环绕通知:MethodInterceptor

实现步骤如下:

1. 业务接口实现

package com.lxl.www.aop.interfaceAop;

/**
 * 使用接口方式实现AOP,默认通过JDK的动态代理来实现. 非接口方式,使用的是cglib实现动态代理
 *
 * 业务接口类-- 计算器接口类
 *
 * 定义三个业务逻辑方法
 */
public interface IBaseCalculate {

    int add(int numA,int numB);

    int sub(int div(int multi(int mod( numB);

}

 

2. 业务类

package com.lxl.www.aop.interfaceAop;//业务类,也是目标对象

import com.lxl.www.aop.Calculate;

import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;

*
 * 业务实现类 -- 基础计算器
 */
@Service
class BaseCalculate implements IBaseCalculate {

    @Override
     numB) {
        System.out.println("执行目标方法: add");
        return numA + numB;
    }

    @Override
    执行目标方法: subreturn numA -执行目标方法: multireturn numA *执行目标方法: divreturn numA /执行目标方法: mod);

        int retVal = ((Calculate) AopContext.currentProxy()).add(numA,numB);
        return retVal % numA;
    }
}

 

3. 通知类

前置通知

package com.lxl.www.aop.interfaceAop;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

*
 * 定义前置通知
 
@Component
 BaseBeforeAdvice implements MethodBeforeAdvice {

    *
     *
     * @param method 切入的方法
     * @param args 切入方法的参数
     * @param target 目标对象
     * @throws Throwable
     
    @Override
    void before(Method method,Object[] args,Object target) throws Throwable {
        System.===========进入beforeAdvice()============);

        System.目标对象:" + target);
        System.方法名: "+method);

        System.即将进入切入点方法);
    }

}

 

后置通知

package com.lxl.www.aop.interfaceAop;

import org.aspectj.lang.annotation.AfterReturning;
import org.springframework.aop.Afteradvice;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

 BaseAfterReturnAdvice implements AfterReturningAdvice {

    *
     *
     * @param returnValue 切入点执行完方法的返回值,但不能修改
     * @param method 切入点方法
     * @param args 切入点方法的参数数组
     * @param target 目标对象
     * @throws Throwable
      afterReturning(Object returnValue,Method method,1)">==========进入afterReturning()=========== \n);
        System.切入点方法执行完成后置通知--目标对象:后置通知--方法名: method);
        System.后置通知--方法入参:  args.toString());
        System.后置通知--方法返回值:  returnValue);
    }

}

 

异常通知

package com.lxl.www.aop.interfaceAop;

import org.springframework.aop.ThrowsAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
@Component
 BaseAfterThrowsAdvice implements ThrowsAdvice {

    *
     * @param method    可选:切入的方法
     * @param args      可选:切入的方法的参数
     * @param target    可选:目标对象
     * @param throwable 必填 : 异常子类,出现这个异常类的子类,则会进入这个通知。
     */
     afterThrowing(Method method,Object target,Throwable throwable) {
        System.出错啦);
    }
}

 

环绕通知

package com.lxl.www.aop.interfaceAop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

*
 * 环绕通知
  BaseAroundAdvice implements MethodInterceptor {

    *
     * invocation :连接点
     public Object invoke(MethodInvocation invocation) throws Throwable {
        System.===========around环绕通知方法 开始=========== 调用目标方法之前执行的动作
        System.环绕通知--调用方法之前: 执行 调用方法的参数
        Object[] args = invocation.getArguments();
         调用的方法
        Method method = invocation.getmethod();
         获取目标对象
        Object target = invocation.getThis();
        System.输入参数:" + args[0] + ;" + method +  target);

         执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
        Object returnValue = invocation.proceed();

        System.环绕通知--调用方法之后: 执行);
      
        System.输出参数:" + target +  returnValue);

        System.===========around环绕通知方法  结束===========return returnValue;
    }

}

 

4. 自定义切点

*
 * 切点
 *
 * 继承NameMatchMethodpointcut类,来用方法名匹配
 
import org.springframework.aop.support.NameMatchMethodpointcut;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
 pointcut extends NameMatchMethodpointcut {

    private static final long serialVersionUID = 3990456017285944475L;

    @SuppressWarnings(rawtypes)
    @Override
     boolean matches(Method method,Class targetClass) {
         设置单个方法匹配
        this.setMappedname(add 设置多个方法匹配
        String[] methods = { ",div };
      
        也可以用“ * ” 来做匹配符号
         this.setMappedname("get*");
      
        this.setMappednames(methods);

         super.matches(method,targetClass);
    }

}

 

5. 配置xml文件

<?xml version=1.0" encoding=UTF-8"?>
<beans xmlns=http://www.springframework.org/schema/beans
       xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
       xmlns:p=http://www.springframework.org/schema/p
       xmlns:context=http://www.springframework.org/schema/context
       xmlns:aop=http://www.springframework.org/schema/aop
       xsi:schemaLocation="
          http:www.springframework.org/schema/beans
          http:www.springframework.org/schema/beans/spring-beans-3.0.xsd

          http:www.springframework.org/schema/context
          http:www.springframework.org/schema/context/spring-context-3.0.xsd

         http:www.springframework.org/schema/aop
          http:www.springframework.org/schema/aop/spring-aop-3.0.xsd"
>

    <!-- ==============================aop配置================================ -->
    <!-- 声明一个业务类 -->
    <bean id=baseCalculate" class=com.lxl.www.aop.interfaceAop.BaseCalculate"/>

    <!-- 声明通知类 -->
    <bean id=baseBeforecom.lxl.www.aop.interfaceAop.BaseBeforeAdvice"/>
    <bean id=baseAfterReturncom.lxl.www.aop.interfaceAop.BaseAfterReturnAdvicebaseAfterThrowscom.lxl.www.aop.interfaceAop.BaseAfterThrowsAdvicebaseAroundcom.lxl.www.aop.interfaceAop.BaseAroundAdvice"/>

    <!-- 指定切点匹配类 -->
    <bean id=pointcutcom.lxl.www.aop.interfaceAop.pointcut"/>

    <!-- 包装通知,指定切点 -->
    <bean id=matchBeforeAdvisororg.springframework.aop.support.DefaultpointcutAdvisor">
        <property name=">
            <ref bean="/>
        </property>
        <property name=advice"/>
        </property>
    </bean>

    <!-- 使用Proxyfactorybean 产生代理对象 -->
    <bean id=businessProxyorg.springframework.aop.framework.Proxyfactorybean">
        <!-- 代理对象所实现的接口 ,如果有接口可以这样设置 -->
        <property name=proxyInterfaces">
            <value>com.lxl.www.aop.interfaceAop.IBaseCalculate</value>
        </property>

        <!-- 设置目标对象 -->
        <property name=target"/>
        </property>
        <!-- 代理对象所使用的拦截器 -->
        <property name=interceptorNames">
            <list>
                <value>matchBeforeAdvisor</value>
                <value>baseAfterReturn</value>
                <value>baseAround</value>
            </list>
        </property>
    </bean>
</beans>

 

6. 方法入口

package com.lxl.www.aop.interfaceAop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClasspathXmlApplicationContext;

 InterfaceMainClass{

    static  main(String[] args) {
        ApplicationContext context = new ClasspathXmlApplicationContext(aop/aop.xml);
        BaseCalculate calculate = (BaseCalculate) context.getBean();
        calculate.add(1,1)">3);
    }

}

 

三. 分析

各种类型通知的执行顺序: 前置方法会在切入点方法之前执行,后置会在切入点方法执行之后执行,环绕则会在切入点方法执行前执行同事方法结束也会执行对应的部分。主要是调用proceed()方法来执行切入点方法。来作为环绕通知前后方法的分水岭

在xml 配置 businessProxy这个bean的时候,Proxyfactorybean类中指定了,proxyInterfaces参数。这里把他配置了IBaseCalculate接口。因为在项目开发过程中,往往业务类都会有对应的接口,以方便利用IOC解耦。但Spring AOP却也能支持没有接口的代理。这就是为什么需要导入cglib.jar包了。看过spring的源码,知道在目标切入对象如果有实现接口,spring会默认使用jdk动态代理来实现代理类。如果没有接口,则会通过cglib来实现代理类。

  这个业务类现在有 前置通知,后置通知,环绕三个通知同时作用,可能以及更多的通知进行作用。那么这些通知的执行顺序是怎么样的?就这个例子而言,同时实现了三个通知。在例 子xml中,则显示执行before通知,然后执行around的前处理,执行切点方法,再执行return处理。最后执行around的后处理。经过测 试,知道spring 处理顺序是按照xml配置顺序依次处理通知,以队列的方式存放前通知,以压栈的方式存放后通知。所以是前通知依次执行,后通知到切入点执行完之后,从栈里 在后进先出的形式把后通知执行。
  在实现过程中发现通知执行对应目标对象的整个类中的方法,如何精确到某个方法,则需要定义一个切点匹配的方式:spring提供了方法名匹配或正则方式来匹配。然后通过DefaultpointcutAdvisor来包装通知,指定切点。

 使用接口方式配置起来,可见代码还是非常的厚重的,定义一个切面就要定义一个切面类,然而切面类中,就一个通知方法,着实没有必要。所以Spring提供了,依赖aspectj的schema配置和基于aspectj 注解方式。这两种方式非常简单方便使用,也是项目中普遍的使用方式。

 

Idea环境实现SpringBoot实现两种热部署方式(亲测有效)

Idea环境实现SpringBoot实现两种热部署方式(亲测有效)

即将介绍的两种热部署方式:

  1.SpringLoaded

  2.DevTools

区别:

  SpringLoaderSpringLoader 在部署项目时使用的是热部署的方式。

 DevToolsDevTools 在部署项目时使用的是重新部署的方式




SpringBoot版本:2.1.9-RELEASE

IDEA版本:2019.2.4

热部署

  大家都知道在项目开发过程中,常常会改动页面数据或者修改数据结构,为了显示改动效果,往往需要重启应用查看改变效果,其实就是重新编译生成了新的Class文件,这个文件里记录着和代码等对应的各种信息,然后Class文件将被虚拟机的ClassLoader加载。

而热部署正是利用了这个特点,它监听到如果有Class文件改动了,就会创建一个新的ClaassLoader进行加载该文件,经过一系列的过程,最终将结果呈现在我们眼前。

 

类加载机制

  Java中的类经过编译器可以把代码编译为存储字节码的Class文件,该Class文件存储了各种信息,最终要加载到虚拟机中运行使用。

  虚拟机把描述类的数据从Class文件加载到内存中,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。

 

 

 


 

SpringLoaded 实现热部署方式:

缺陷:不会加载静态资源,只加载类文件,也就是只热部署加载class

  1.到mvn仓库下载jar包

 

 

 

 

 

 下载后记住这个jar包的绝对路径。接下来会用到

 

  2.配置SpringBoot的启动参数配置

 

在VMOptions里面添加 -javaagent:jar包路径 -noverify

 

 

 3.以Debug模式进行启动,再更改代码后会自动更新classes文件,至此完成。

 

 


 

 

DevTools实现热部署方式(自重启)

在激活了开发者工具后,ClassPath里对文件做任何修改都会触发应用程序重启。为了让重启的速度够快,不会修改的类(第三方JAR包)都加载到了基础类加载器里,而应用程序的代码则会加载到一个单独的重启类加载器里。检测到变更时,只会重启类加载 器重启。

  有些ClassPath里的资源变更后不需要重启应用程序。像Thymeleaf这样的视图模板可以直接编辑,不用重启。在/static 或 /public里的静态资源也不用重启应用程序,所以Spring Boot开发者工具在重启时排除掉了如下目录:/META-INF/resources、/resources、/static、/public、/templates。

一、pom依赖

 

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
            <!--    optional目的是为了继承他的项目不继承这个devtools插件        -->
  </dependency>


<build>
        <plugins>
                <plugin>
                    <!--热部署配置-->
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <!--fork:如果没有该项配置,整个devtools不会起作用(根据个人情况而定,最好加上)-->
                        <fork>true</fork>
                    </configuration>
                </plugin>
        </plugins>
    </build>

 

二、勾选Build project automatically(自动构建)

 

 

三、IDEA 设置为在程序运行过程中,依然允许自动编译

步骤: ctrl + shift + alt + /,选择Registry,勾选勾上 Compiler autoMake allow when app running

 

 

 

 勾选目标的位置自己找找,排列顺序不一样,勾选后记得重启生效!

 

四、设置自动加载资源配置和编译

 

 

 

就此全部完成,有什么问题欢迎随时留言,远程协助~

 

 

 

 

 

原文出处:https://www.cnblogs.com/arebirth/p/springboothotdeploy.html

Intellij IDEA实现SpringBoot项目多端口启动的两种方法

Intellij IDEA实现SpringBoot项目多端口启动的两种方法

前言

有时候使用springboot项目时遇到这样一种情况,用一个项目需要复制很多遍进行测试,除了端口号不同以外,没有任何不同。这时我们强大的Intellij IDEA就能替我们实现。

实现方法

第一种方法

1.点击图中Edit Configurations,如图

2.取消选中的Single instance only

3.启动项目,demo(9000),如图。

4.修改配置文件中的端口号为9001,启动项目,demo(9001),如图。

从下方可以看到demo项目分别以9000和9001启动了。

第二种方法

1.点击图中Edit Configurations,如图

2.点击左上角+号,选择Spring Boot

3.点击...位置,如图

4.选择需要启动的项目,点击ok

5.将上方name修改为demo2

6.启动demo(9000),如图

7.修改端口为9001,启动demo2,如图

到这里第二种方法也结束了

总结

两种方法都可以实现想要达到的效果,但是个人觉得第一种相对简单一些。具体怎么使用看个人喜好。希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!

您可能感兴趣的文章:

  • intellij idea tomcat热部署配置教程
  • IntelliJ IDEA使用maven实现tomcat的热部署
  • SpringBoot项目在IntelliJ IDEA中如何实现热部署
  • IntelliJ IDEA配置Tomcat(完整版图文教程)
  • IntelliJ IDEA Tomcat配置详解(图文)
  • 使用IntelliJ IDEA搭建SSM框架的图文教程
  • Intellij idea远程debug连接tomcat实现单步调试
  • IntelliJ IDEA 最常用的配置图文详解

Java中5种方式实现String反转

Java中5种方式实现String反转

这里介绍java中5中实现string反转的方式。

一、数组实现String反转

//数组实现String反转
  public String reverseByArray(){
    if(str == null || str.length() == 1){
      return null;
    }
    char[] ch = str.toCharArray();//字符串转换成字符数组
    for(int i = 0 ; i < ch.length/2 ; i++){
      char temp = ch[i];
      ch[i] = ch[ch.length-i-1];
      ch[ch.length-i-1] = temp;
    }
    return new String(ch);
  }
登录后复制

二、栈实现String反转

//用栈实现String反转
  public String reverseByStack(){
    if(str == null || str.length() == 1){
      return null;
    }
    Stack<Character> stack = new Stack<Character>();
    char[] ch = str.toCharArray();//字符串转换成字符数组
    for (char c : ch) {
      stack.push(c);//每个字符,推进栈
    }
    for (int i = 0; i < ch.length; i++) {
      ch[i] = stack.pop();//移除这个堆栈的顶部对象
    }
    return new String(ch);
  }
登录后复制


三、逆序遍历实现String反转

立即学习“Java免费学习笔记(深入)”;

//用逆序遍历实现String反转
 
  public String reverseBySort(){
    if(str == null || str.length() == 1){
      return null;
    }
    StringBuffer sb = new StringBuffer();
    for (int i = str.length() -1 ; i >= 0; i--) {
      sb.append(str.charAt(i));//使用StringBuffer从右往左拼接字符
    }
    return sb.toString();
  }
登录后复制

四、位运算实现String反转

//使用位运算实现String反转
  public String reverseByBit() {
    if(str == null || str.length() == 1){
      return null;
    }
    char[] ch = str.toCharArray();//字符串转换成字符数组
    int len = str.length();
    for(int i= 0; i< len/ 2; i++) {
      ch[i]^= ch[len- 1- i];
      ch[len- 1- i]^= ch[i];
      ch[i]^= ch[len- 1- i];
    }
    return new String(ch);
  }
登录后复制

五、递归实现String反转

//使用递归实现String反转
  public String reverseByRecursive(String str){
    if(str == null || str.length() == 0){
      return null;
    }
    if(str.length() == 1){
      return str;
    } else {
      //从下标为1开始截取字符串,在返回下标为0的字符
      return reverseByRecursive(str.substring(1)) + str.charAt(0);
    }
  }
登录后复制

六、测试

public class Test {
  public static void main(String[] args) {
    String s = "123456";
    Reverse r = new Reverse(s);
    System.out.println(r.reverseByArray());
    System.out.println(r.reverseByStack());
    System.out.println(r.reverseBySort());
    System.out.println(r.reverseByBit());
    System.out.println(r.reverseByRecursive(s));
     
  }
}
登录后复制

七、结果

Java中5种方式实现String反转

八、用于String反转的全部代码

public class Reverse {
  private String str = null;
   
  public Reverse(String str){
    this.str = str;
  }
   
  //数组实现String反转
  public String reverseByArray(){
    if(str == null || str.length() == 1){
      return null;
    }
    char[] ch = str.toCharArray();//字符串转换成字符数组
    for(int i = 0 ; i < ch.length/2 ; i++){
      char temp = ch[i];
      ch[i] = ch[ch.length-i-1];
      ch[ch.length-i-1] = temp;
    }
    return new String(ch);
  }
  //用栈实现String反转
  public String reverseByStack(){
    if(str == null || str.length() == 1){
      return null;
    }
    Stack<Character> stack = new Stack<Character>();
    char[] ch = str.toCharArray();//字符串转换成字符数组
    for (char c : ch) {
      stack.push(c);//每个字符,推进栈
    }
    for (int i = 0; i < ch.length; i++) {
      ch[i] = stack.pop();//移除这个堆栈的顶部对象
    }
    return new String(ch);
  }
  //用逆序遍历实现String反转
  public String reverseBySort(){
    if(str == null || str.length() == 1){
      return null;
    }
    StringBuffer sb = new StringBuffer();
    for (int i = str.length() -1 ; i >= 0; i--) {
      sb.append(str.charAt(i));//使用StringBuffer从右往左拼接字符
    }
    return sb.toString();
  }
  //使用位运算实现String反转
  public String reverseByBit() { 
    if(str == null || str.length() == 1){
      return null;
    }
    char[] ch = str.toCharArray();//字符串转换成字符数组
    int len = str.length(); 
    for(int i= 0; i< len/ 2; i++) { 
      ch[i]^= ch[len- 1- i]; 
      ch[len- 1- i]^= ch[i]; 
      ch[i]^= ch[len- 1- i]; 
    }
    return new String(ch);
  }
  //使用递归实现String反转
  public String reverseByRecursive(String str){
    if(str == null || str.length() == 0){
      return null;
    }
    if(str.length() == 1){
      return str;
    } else {
      //从下标为1开始截取字符串,在返回下标为0的字符
      return reverseByRecursive(str.substring(1)) + str.charAt(0);
    }
  }
}
登录后复制

以上这篇Java中5种方式实现String反转就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持PHP中文网。

更多Java中5种方式实现String反转相关文章请关注PHP中文网!

关于两种方式实现Spring 业务验证spring数据验证的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于5.3 Spring5源码--Spring AOP使用接口方式实现、Idea环境实现SpringBoot实现两种热部署方式(亲测有效)、Intellij IDEA实现SpringBoot项目多端口启动的两种方法、Java中5种方式实现String反转的相关知识,请在本站寻找。

本文标签:

上一篇itlab→jenkins→registry→kubernetes→docker

下一篇vue之Promise、Fetch、Axios入门以及学习总结,涉及Express搭建接口(vue promise axios)