"4S"框架快速构建优雅的Java服务

前言

"4S"框架是我为了区别传统的SSH和SSM说法,提出的一个叫法。自从有了Spring MVC,特别是Spring Boot后,Java服务已经从臃肿的配置中解放出来。Java 服务也能够知足快速构建的须要,迭代速度上并不比PHP,NodeJS差什么。可是不少公司的Java技术栈过于陈旧,没法发挥Java的现有优点。本文主要阐述如何快速优雅的构建一个完整的Java工程。本文提供4S框架的工程化方案javascript

内容包括:html

  • 工程构建
  • 包结构设计
  • 工程配置
  • 业务配置
  • ORM层实现

本文意图:前端

  • 提升企业开发的效率
  • 优化项目结构
  • "4S"是个单体服务,可是能够为"5S"(+Spring Cloud)构建微服务提供基础

1.0 从SSH和SSM到"4S"

  • SSH:Structs(控制层),hibernate(ORM),Spring
  • SSM:SpringMVC(控制层),MyBatis(ORM),Spring

以上就是Java服务中最多见的框架思路。这3个最多见的框架之间涉及到框架的整合,并且框架自己的使用也涉及到大量的配置,如MyBatis的Mapping文件。若是能去掉这些框架整合的部分,固然不光是这三个框架的整合,实际业务还包括缓存,消息中间件等大量框架的整合,会十分的美好。若是再优化下ORM映射的过程,会更加的美好。因而有了"4S"。java

  • "4S":SpringMVC(控制层),Spring Data JPA(ORM),Spring Boot(自动化配置),Spring

2.0 "4S"工程建立

推荐IntelliJ IDEA构建Spring Boot项目。动手点一点,三步搞定一个Spring Boot的Maven工程,就问你简单不简单?
mysql

第一步

第二步

第三步

搞定后,找到包的根目录下的Application文件,运行main函数,一个Java服务就启动了,连Tomcat都不用配置。web

3.0 工程包结构设计

提供一种基于4S框架的分包思路,供参考。spring

  • 1是工程相关的配置信息。
  • 2是数据库相关的业务信息。bean中维护了与数据库表结构对应的信息。repository代替传统的dao层,维护数据库的操做。
  • 3是全局的业务相关的配置信息。包括全局的异常处理,拦截器,工具类,全局缓存。
  • 4是业务的主体。这里只分为2层,controller中是控制层,service中是业务处理主体。
  • 5和/resource/value目录对应。用配置的方式来维护一些常量,相似于以前的constance的做用。
  • 6是程序的入口,由于Spring Boot的配置信息会自动扫描和该文件同级的目录及其子目录的信息,故放在根目录下。
  • 7是前端框架
  • 8是前端页面
  • 9是工程的配置文件

4.0 工程配置

4.1 不一样环境配置

开发环境和测试环境链接的数据库和一些配置信息不一样,能够经过在application.properties指定不一样的配置文件sql

# 配置环境 正式环境release 开发环境debug
spring.profiles.active=debug复制代码

而后在application-debug.properties中配置测试环境信息,在application-release.properties中配置正式环境信息。数据库

4.2 日志配置

日志配置很简单,在application.properties作点配置便可,列举几条经常使用的缓存

# 日志地址
logging.file=D:/springBoot/log.log
# 日志打印级别
logging.level.org.springframework.web=DEBUG复制代码

4.3 常量

/value/JavaBean 和 /resource/value/xxx.properties 创建一一对应的关系。能够经过Bean对象获取xxx.properties中的常量信息。举个例子。

/resource/value/user.properties

user.name=wolearn
user.age=12复制代码
/java/包名/value/UserProperty.java

@Component
@ConfigurationProperties(prefix = "user", ignoreUnknownFields = false)
@PropertySource("classpath:/value/user.properties")
public class UserProperty {
    private String name;
    private Long age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getAge() {
        return age;
    }

    public void setAge(Long age) {
        this.age = age;
    }
}复制代码

对应的配置文件和JavaBean创建完毕后,能够直接经过注解注入,直接获取常量的值。

@Resource
private UserProperty userProperty;

public static void main(String[] args) {
    System.out.print("name: " + userProperty.getName() + " age: " + userProperty.getAge();")
}复制代码

5.0 业务配置

5.1 全局异常处理

能够使用AOP或者@ControllerAdvice注解来作全局控制。这里使用注解的形式作全局的异常处理。发生异常时,跳转到error.html页面。

/java/包名/global/advice

@org.springframework.web.bind.annotation.ControllerAdvice
public class ControllerAdvice {

    /** * 统一处理异常 * @param exception * @param webRequest * @return */
    @ExceptionHandler(Exception.class)
    public ModelAndView exception(Exception exception, WebRequest webRequest) {
        return new ModelAndView("error");
    }

}复制代码

5.2 简单视图映射

有些简单的请求,直接返回视图的,不用直接新建一个完整的controller,能够经过配置直接路由。

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 路由和视图映射
        registry.addViewController("/user").setViewName("/user");
    }
}复制代码

当访问/user路由时,直接返回user.html页面。

5.3 拦截器

在请求的先后,对全局的请求作拦截。

/** * Created by wulei on 2017/6/8. * * 全局的时间拦截器 */
public class TimeInterceptor extends HandlerInterceptorAdapter{
    private static Logger logger = Logger.getLogger(TimeInterceptor.class);

    /** * 请求执行前 */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.debug(request.getServletPath() + " StartTime:" + System.currentTimeMillis());
        return super.preHandle(request, response, handler);
    }

    /** * 请求执行后 */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.debug(request.getServletPath() + " EndTime:" + System.currentTimeMillis());
        super.postHandle(request, response, handler, modelAndView);
    }
}复制代码

拦截器定义完成后,要在配置类中实例化。

/** * Created by wulei on 2017/6/8. * * 从新配置MVC */
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor());
    }

    @Bean
    public TimeInterceptor timeInterceptor(){
        return new TimeInterceptor();
    }
}复制代码

6.0 ORM层设计

6.1 链接MySQL

在application.properties配置数据库链接信息

# -----------    DB    --------------------
spring.jpa.database=MYSQL
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test_spring_boot?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root复制代码

Maven中配置JDBC依赖和Spring Data JPA的依赖。JPA是Spring Data的子项目,能够有效减小数据访问层的代码。

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>复制代码

6.2 正向工程建表

咱们能够经过定义Bean来定义表结构,并经过正向工程直接在数据库中生成相应的表。举个User的例子。

@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;

    private Integer age;

    private String name;

    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}复制代码
  • @Entity 声明这是一个跟数据库有映射关系的实体类
  • @Id 声明主键ID
  • @GeneratedValue 声明自增加

当工程启动的时候,自动生成数据库表。

6.3 数据库操做

经过继承JpaRepository接口,实现数据库操做。JpaRepository已经实现了一些基本的数据库操做

public interface UserRepository extends JpaRepository<User, Long> {
    // 按照地址查询地址
    List<User> findByAddress(String name);
}复制代码

简单数据库操做能够直接调用JpaRepository接口中定好的方法。如保存一个User对象。

@Autowired
    public UserRepository userRepository;

    public static void main(String[] args) {
        User user = new User();
        user.setName(name);
        user.setAddress(address);
        user.setAge(age);
        userRepository.save(user);
     }复制代码

直接注入一个Repository。若是要自定义一个查询地址的方法如上findByAddress便可。更多操做能够参考官方文档。

docs.spring.io/spring-data…

后话

仍是不少东西能够聊,如构建权限控制,缓存的使用,事务的使用,后面慢慢聊。喜欢欢迎点赞,打赏。

相关文章
相关标签/搜索