java开发常用的工具以及配置类

java前后端分离开发常用的配置
针对在java开发中常用的配置 工具设置做一个总结

1 简化开发 提高效率 利用 mybatis-plus
第一步 maven构建项目,pom.xml引入依赖坐标

 <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.3.1version>
  dependency>

在项目主目录的config包创建配置类MybatisPlusConfig

@Configuration  // 添加注解;
@EnableTransactionManagement  // 开启事务注解
@MapperScan("包名")  // 包名扫描mapper包;  这里如果配置了,SpringBoot主启动类可以不用加@MapperScan注解
public class MybatisPlusConfig {
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();  // 乐观锁配置;
    }
    @Bean
    public PaginationInterceptor paginationInterceptor(){  
        return new PaginationInterceptor();  // 分页配置;
    }
    }

注意。如果你的mybatis-plus版本是mybatis-plus 3.4.0后的版本,那么配置就该如下了:

		@Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 分页;
            interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());//乐观锁
            return interceptor;
    }

需要添加其他配置的话,就是设置interceptor,将其返回即可。

需要使用mybatis-plus的自动生成代码,创建实体类,service及其实现类,controller类等功能,需要进行以下步骤:
1 pom.xml引入依赖坐标

<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-generatorartifactId>
    <version>${mybatis-plus.version}version>
dependency>

<dependency>
    <groupId>org.apache.velocitygroupId>
    <artifactId>velocity-engine-coreartifactId>
    <version>${velocity.version}version>
dependency>

${mybatis-plus.version} 和 ${velocity.version}是版本。

2 代码生成器类:

public class CodeGenerator {

    @Test // 如果pom.xml测试是junit,就不需要@RunWith,junit单元测试不需要依赖Spring上下文环境;
    public void genCode() {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");  // projectPath 获取的是就是x项目的根目录;
        gc.setOutputDir(projectPath + "/src/main/java");  // java代码的位置;
        gc.setAuthor("boger"); // 设置作者
        gc.setOpen(false); //生成后是否打开资源管理器; 一般不打开;
        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        gc.setIdType(IdType.AUTO); //主键策略
        gc.setSwagger2(true);//开启Swagger2模式
        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/数据库名?serverTimezone=GMT%2B8&characterEncoding=utf-8");
        dsc.setDriverName("com.mysql.jdbc.Driver"); // 数据库驱动;
        // 如果是mysql8.0版本,驱动就是com.mysql.cj.jdbc.Driver
        dsc.setUsername("数据库用户名");
        dsc.setPassword("数据库密码");
        dsc.setDbType(DbType.MYSQL);  /// 数据库类型;
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("源代码的包名");
        pc.setEntity("pojo.entity"); //此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
        mpg.setPackageInfo(pc);
        
        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 生成@Data的注解;

        strategy.setLogicDeleteFieldName("is_deleted");  //逻辑删除字段名,加入逻辑删除注解;
        strategy.setEntityBooleanColumnRemoveIsPrefix(true);  //去掉布尔值的is_前缀(确保tinyint(1))
        strategy.setRestControllerStyle(true); //restful api风格控制器,在Controller类上添加@RestController注解;
        mpg.setStrategy(strategy);

        // 6、执行
        mpg.execute();
    }
}

运行此文件,就会把对应数据库的表结构,转换为java的实体类,并且会生成对应的mapper和xml,service 及其实现类 controller类。并且会加上相应的注解。简化创建实体 Java类。

对于数据库表结构的如果有创建时间(create_time) 更新时间(update_time)字段。如果需要根据业务的插入 更新来改变,有两种方法。
方法一: 数据库表结构的此字段 设计表勾选根据当前时间戳更新。
方法二: 先在实体类的对应字段添加注解。例如创建时间和更新时间。

 @TableField(fill = FieldFill.INSERT)    // 数据库字段是create_time,实体类是createTime,不需要做字段映射,Mybatisplus自动映射;
  private Date createTime;
  @TableField(fill = FieldFill.INSERT_UPDATE)
  private Date updateTime;

在配置包下面添加配置类MyMetaObjectHandler

@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
	 public void insertFill(MetaObject metaObject) {
        log.info("插入时自动填充");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
     }
	
	 public void updateFill(MetaObject metaObject) {
        log.info("更新时自动填充");
        this.setFieldValByName("updateTime",new Date(),metaObject)}
}

注意 createTime updateTime 和实体类对应。

同时,注意代码生成器默认将mapper和对应的xml放在了src/main/java目录下。此时启动springboot项目,会出错。因为mapper和xml文件默认是放在资源目录下,即在resources目录下。此时,我们需要在pom.xml里面配置以下内容:

<build>
        <resources>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>falsefiltering>
            resource>
        resources>
 build>

重新编译,启动就不会出错了。

2 统一结果返回类。
前后端开发,设置统一结果返回类,restful风格开发。

@Data  // pom.xml需要lombok依赖
public class R {
    private Integer code;  // 返回状态码;
    private String message; // 返回消息;
    private Map<String, Object> data = new HashMap<>();   // 返回数据;

    /**
     * 构造器私有
     */
    private R(){}

    /**
     * 返回成功
     */
    public static R ok(){
        R r = new R();
        r.setCode(ResponseEnum.SUCCESS.getCode());
        r.setMessage(ResponseEnum.SUCCESS.getMessage());
        return r;
    }

    /**
     * 返回失败
     */
    public static R error(){
        R r = new R();
        r.setCode(ResponseEnum.ERROR.getCode());
        r.setMessage(ResponseEnum.ERROR.getMessage());
        return r;
    }

    /**
     * 设置特定结果
     */
    public static R setResult(ResponseEnum responseEnum){
        R r = new R();
        r.setCode(responseEnum.getCode());
        r.setMessage(responseEnum.getMessage());
        return r;
    }

    /**
     * 设置特定的响应信息;
     * @param message
     * @return
     */
    public R message(String message){
        this.setMessage(message);
        return this;
    }

    /**
     * 设置特定的响应码;
     * @param code
     * @return
     */
    public R code(Integer code){
        this.setCode(code);
        return this;
    }


    public R data(String key, Object value){
        this.data.put(key, value);
        return this;
    }


    public R data(Map<String, Object> map){
        this.setData(map);
        return this;
    }
}

统一结果返回,每次后端返回的结果封装到R类中。R类设置返回的状态码 返回消息 以及数据。比如某个业务需要执行成功(不需要返回数据),我们返回
{
“code":200,
“message”,执行成功
}
如果执行成功并返回数据,我们返回
{
“code":200,
“message”,执行成功,
“data":需要返回的数据
}
这样的话,统一用json格式返回给前端。前端从Json数据取就可以了。

3 针对密码加密类 这里以MD5加密工具为例.

public final class MD5 {

    public static String encrypt(String strSrc) {
        try {
            char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
                    '9', 'a', 'b', 'c', 'd', 'e', 'f' };
            byte[] bytes = strSrc.getBytes();
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(bytes);
            bytes = md.digest();
            int j = bytes.length;
            char[] chars = new char[j * 2];
            int k = 0;
            for (int i = 0; i < bytes.length; i++) {
                byte b = bytes[i];
                chars[k++] = hexChars[b >>> 4 & 0xf];
                chars[k++] = hexChars[b & 0xf];
            }
            return new String(chars);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException("MD5加密出错!!+" + e);
        }
    }

    public static void main(String[] args) {
        String  s = "hello";
        System.out.println("加密后的结果为"+ encrypt(s)); // 5d41402abc4b2a76b9719d911017c592
    }
}

4 随机生成验证码工具 (常用于生成手机验证码业务 – 这里针对4或者6位的数字验证码)

public class RandomUtils {

	private static final Random random = new Random();
	private static final DecimalFormat fourdf = new DecimalFormat("0000");
	private static final DecimalFormat sixdf = new DecimalFormat("000000");
	public static String getFourBitRandom() {
		return fourdf.format(random.nextInt(10000));
	}

	public static String getSixBitRandom() {
		return sixdf.format(random.nextInt(1000000));
	}
	}

5 正则表达式工具 (用于校验 手机号 QQ号 身份证 邮箱工具等业务)

public class RegexValidateUtils {

    static boolean flag = false;
    static String regex = "";

    public static boolean check(String str, String regex) {
        try {
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(str);
            flag = matcher.matches();
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }

    /**
     * 验证邮箱
     * @param email
     * @return
     */
    public static boolean checkEmail(String email) {
        String regex = "^\\w+[-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$ ";
        return check(email, regex);
    }

    /**
     * 验证手机号码
     * 移动号码段:139、138、137、136、135、134、150、151、152、157、158、159、182、183、187、188、147
     * 联通号码段:130、131、132、136、185、186、145
     * 电信号码段:133、153、180、189
     * @param cellphone
     * @return
     */
    public static boolean checkCellphone(String cellphone) {
        String regex = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$";
        return check(cellphone, regex);
    }

    /**
     * 验证固话号码
     * @param telephone
     * @return
     */
    public static boolean checkTelephone(String telephone) {
        String regex = "^(0\\d{2}-\\d{8}(-\\d{1,4})?)|(0\\d{3}-\\d{7,8}(-\\d{1,4})?)$";
        return  check(telephone, regex);
    }

    /**
     * 验证传真号码
     * @param fax
     * @return
     */
    public static boolean checkFax(String fax) {
        String regex = "^(0\\d{2}-\\d{8}(-\\d{1,4})?)|(0\\d{3}-\\d{7,8}(-\\d{1,4})?)$";
        return check(fax, regex);
    }

    /**
     * 验证QQ号码
     * @param QQ
     * @return
     */
    public static boolean checkQQ(String QQ) {
        String regex = "^[1-9][0-9]{4,} $";
        return check(QQ, regex);
    }
}

6 统一异常处理类以及自定义异常类

@Slf4j
@Component 		//Spring容易自动管理
@RestControllerAdvice 	//在controller层添加通知。如果使用@ControllerAdvice,则方法上需要添加@ResponseBody  使用的是AOP切面编程;
public class UnifiedExceptionHandler {

    @ExceptionHandler(value = Exception.class)    //当controller中抛出Exception,则捕获
    public R handleException(Exception e){
        log.error(e.getMessage(),e); // 打印日志;
        return R.error();
    }

    /**
     * 特定异常  SQL异常;
     */
    @ExceptionHandler(BadSqlGrammarException.class)
    public R handleBadSqlGrammarException(BadSqlGrammarException e){
        log.error(e.getMessage(), e);
        return R.setResult(ResponseEnum.BAD_SQL_GRAMMAR_ERROR);  // 返回特定的响应码;
    }

    /**
     * 捕捉自定义异常类;  只需在业务层抛出自定义异常; throw new  BusinessException(枚举响应码,响应信息)
     * @param e
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    public R handleBusinessException(BusinessException e){
        log.error(e.getMessage(),e);
        return R.error().message(e.getMessage()).code(e.getCode());
    }

    /**
     * Controller上一层相关异常;  即未进入controller方法之前执行的异常;
     */
    @ExceptionHandler({
            NoHandlerFoundException.class,
            HttpRequestMethodNotSupportedException.class,
            HttpMediaTypeNotSupportedException.class,
            MissingPathVariableException.class,
            MissingServletRequestParameterException.class,
            TypeMismatchException.class,
            HttpMessageNotReadableException.class,
            HttpMessageNotWritableException.class,
            MethodArgumentNotValidException.class,
            HttpMediaTypeNotAcceptableException.class,
            ServletRequestBindingException.class,
            ConversionNotSupportedException.class,
            MissingServletRequestPartException.class,
            AsyncRequestTimeoutException.class
    })
    public R handleServletException(Exception e) {
        log.error(e.getMessage(), e);
        //SERVLET_ERROR(-102, "servlet请求异常"),
        return R.error().message(ResponseEnum.SERVLET_ERROR.getMessage()).code(ResponseEnum.SERVLET_ERROR.getCode());
    }
}

BusinessException 自定义异常类

@Data
@NoArgsConstructor
public class BusinessException extends RuntimeException{

    private Integer code;
    private String message;

    /**
     * @param message 错误消息
     */
    public BusinessException(String message) {
        this.message = message;
    }

    /**
     *
     * @param message 错误消息
     * @param code 错误码
     */
    public BusinessException(String message, Integer code) {
        this.message = message;
        this.code = code;
    }

    /**
     * @param message 错误消息
     * @param code 错误码
     * @param cause 原始异常对象
     */
    public BusinessException(String message, Integer code, Throwable cause) {
        super(cause);
        this.message = message;
        this.code = code;
    }

    /**
     * @param resultCodeEnum 接收枚举类型
     */
    public BusinessException(ResponseEnum resultCodeEnum) {
        this.message = resultCodeEnum.getMessage();
        this.code = resultCodeEnum.getCode();
    }

    /**
     * @param resultCodeEnum 接收枚举类型
     * @param cause 原始异常对象
     */
    public BusinessException(ResponseEnum resultCodeEnum, Throwable cause) {
        super(cause);
        this.message = resultCodeEnum.getMessage();
        this.code = resultCodeEnum.getCode();
    }
}

要完成统一异常类 和 自定义异常,还需要定义一个枚举类 ResponseEnum。响应枚举类ResponseEnum。可以设置一系列的状态码和信息。
示例如下:

@Getter
@AllArgsConstructor
@ToString
public enum ResponseEnum {
	  // 响应状态码
    private Integer code;
    // 响应信息
    private String message;
    
    SUCCESS(0, "成功"),
    ERROR(-1, "服务器内部错误");
}

7 HttpUtils工具类 简化和抽象HTTP请求和响应的处理过程,提供方便易用的方法,使开发者能够更轻松地与服务器进行通信

@Slf4j
public final class HttpUtils {

	static final String POST = "POST";
	static final String GET = "GET";
	static final int CONN_TIMEOUT = 30000;// ms
	static final int READ_TIMEOUT = 30000;// ms

	/**
	 * post 方式发送http请求.
	 * @param strUrl
	 * @param reqData
	 * @return
	 */
	public static byte[] doPost(String strUrl, byte[] reqData) {
		return send(strUrl, POST, reqData);
	}

	/**
	 * get方式发送http请求.
	 * @param strUrl
	 * @return
	 */
	public static byte[] doGet(String strUrl) {
		return send(strUrl, GET, null);
	}

	/**
	 * @param strUrl
	 * @param reqmethod
	 * @param reqData
	 * @return 
	 */
	public static byte[] send(String strUrl, String reqmethod, byte[] reqData) {
		try {
			URL url = new URL(strUrl);
			HttpURLConnection httpcon = (HttpURLConnection) url.openConnection();
			httpcon.setDoOutput(true);
			httpcon.setDoInput(true);
			httpcon.setUseCaches(false);
			httpcon.setInstanceFollowRedirects(true);
			httpcon.setConnectTimeout(CONN_TIMEOUT);
			httpcon.setReadTimeout(READ_TIMEOUT);
			httpcon.setRequestMethod(reqmethod);
			httpcon.connect();
			if (reqmethod.equalsIgnoreCase(POST)) {
				OutputStream os = httpcon.getOutputStream();
				os.write(reqData);
				os.flush();
				os.close();
			}
			BufferedReader in = new BufferedReader(new InputStreamReader(httpcon.getInputStream(),"utf-8"));
			String inputLine;
			StringBuilder bankXmlBuffer = new StringBuilder();
			while ((inputLine = in.readLine()) != null) {  
			    bankXmlBuffer.append(inputLine);  
			}  
			in.close();  
			httpcon.disconnect();
			return bankXmlBuffer.toString().getBytes();
		} catch (Exception ex) {
			log.error(ex.toString(), ex);
			return null;
		}
	}
	
	/**
	 * 从输入流中读取数据
	 * @param inStream
	 * @return
	 * @throws Exception
	 */
	public static byte[] readInputStream(InputStream inStream) throws Exception {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = inStream.read(buffer)) != -1) {
			outStream.write(buffer, 0, len);
		}
		byte[] data = outStream.toByteArray();// 网页的二进制数据
		outStream.close();
		inStream.close();
		return data;
	}
}

8 Swagger2 接口测试
使用Swagger2 能够方便地测试项目的接口,不需要依赖第三方软件例如postman等
第一步 导入依赖 pom.xml添加


        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger2artifactId>
        dependency>
        
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger-uiartifactId>
        dependency>

第二步 添加配置: Swagger2Config配置类

@Configuration  // 加上注解
@EnableSwagger2   //开启Swagger2
public class Swagger2Config {

    /**
     * 展示包含/admin/路由的路径;
     * @return
     */
    @Bean
    public Docket adminApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("adminApi")
                .apiInfo(adminApiInfo())
                .select()
                //只显示admin路径下的页面
                .paths(Predicates.and(PathSelectors.regex("/admin/.*")))
                .build();
    }

    /**
     * 展示包含/api/的路由;
     * @return
     */
    @Bean
    public Docket webApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select().paths(Predicates.and(PathSelectors.regex("/api/.*")))
                .build();
    }

    /**
     * /admin/的路由添加文档说明;
     * @return
     */
    private ApiInfo adminApiInfo(){
        return new ApiInfoBuilder()
                .title("xxxx管理系统-API文档")
                .description("本文档描述了xxxx管理系统接口")
                .version("1.0")
                .contact(new Contact("boger", "网址", "邮箱"))
                .build();
    }

    /**
     * /api/的路由添加文档说明;
     * @return
     */
    private ApiInfo webApiInfo(){
        return new ApiInfoBuilder()
                .title("xxxx网站-API文档")
                .description("本文档描述了xxxx网站接口")
                .version("1.0")
               .contact(new Contact("boger", "网址", "邮箱"))
                .build();
    }
}

对于路径带有admin表明是后台系统的业务路由,带有api主要针对是前台系统的业务。如果一个接口写好了,我们怎么利用Swagger2 测试接口呢?
启动项目,打开浏览器地址栏访问 localhost:项目端口/swagger-ui.html,利用界面操作测试很方便。

今天就到这里吧,后续继续针对java开发常用的工具以及配置类,进行总结 更新。

你可能感兴趣的:(java,java,spring,boot)