# iBiz SpringMVC模板

（技术引用链接）

`SpringMVC官方文档`[:arrow_upper_right:](https://spring.io/projects/spring-framework)

`iBizSys模型api文档`[:arrow_upper_right:](https://modelapi.ibizlab.cn/)


## 介绍说明

`SpringMVC`

SpringMVC是Spring 框架提供用于构建 Web 应用程序的全功能 MVC 框架。SpringMVC使用了MVC的架构模式思想，将Web层进行指责解耦，并管理应用所需的生命周期，为简化日常开发，提供了很大便利。

`iBizSys`

iBizSys 是以 `Model Driven Development(MDD)`作为核心理论依据的开发框架，iBizSys从`2009年`诞生至今已经经历数个版本，构建出一套完整的系统构建模型，包含: `DevOps模型`、`文档模型`、`流程模型`、`测试模型`等。 iBizSys 提倡以`模型`作为主要内容的高级别抽象的开发方法，并结合市面上较为流行的技术框架形成技术模板，通过`模型`+`模板`的方式快速构建出一套生产级并且具备`复杂性`和`变更能力`的系统。



## 快速开始

## 搭建SpringMVC工程  

本章将通过搭建一个简单的SpringMVC工程为每个实体发布出其对应的Controller用于接收并响应用户请求，在此之前，我们假设您已经：

- **熟悉iBizSys实体建立**

- **熟悉SpringMVC**

- **熟悉FreeMaker**
	

## 建立实体

iBizSys将通过管理数据模型的方式来实现对业务表的管理 [查看更多实体建立小知识](https://bbs.ibizlab.cn/)

![produce](img/quickstart/createEntity.png)

## 建立模板

`编写模板方式`

>在线编辑：`iBizSys` 提供模板在线编辑工具，供大家更高效、便捷的编写模板 [查看iBizSys在线编辑工具](https://bbs.ibizlab.cn/)

>离线编辑：由于`iBizSys`的模板是放在`git`仓库中进行托管，用户可在离线环境下编写模板，编辑完成后再将模板上传至`git`中即可。

### 依赖模板：

在 `pom.xml.ftl` 中引入 SpringMVC 所需的相关依赖

```java

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <junit.version>4.12</junit.version>
        <spring-version>4.2.4.RELEASE</spring-version>
        <jackson.version>2.9.9.3</jackson.version>
        <servlet.version>4.0.1</servlet.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${r'${spring-version}'}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${r'${spring-version}'}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${r'${jackson.version}'}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${r'${junit.version}'}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${r'${servlet.version}'}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${r'${lombok.version}'}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

```
 

### web.xml.ftl模板：

web配置模板文件，模板中含 ` % % 、${ } `均为动态参数 [查看模板参数](https://bbs.ibizlab.cn/)

```java

<?xml version="1.0" encoding="utf-8" ?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>${pub.codeName?lower_case}</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:/ibizsys-dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>${pub.codeName?lower_case}</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>


```

### ibizsys-dispatcher-servlet.xml.ftl模板：

SpringMVC配置模板文件

```java

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="${pub.getPKGCodeName()}.*.rest"/>

    <bean   class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
            </list>
        </property>
    </bean>
</beans>

```




### applicationContext.xml.ftl模板：

Spring配置模板文件

```java

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

```


### %DE%Controller.java.ftl模板：

为每个应用实体发布其对应的Controller

```java

@RestController
public class ${de.codeName}Controller{

    <#assign appReqUrl="/" +app.getPKGCodeName()?lower_case + "/"+de.getPSSystemModule().codeName?lower_case +"/"+de.codeName?lower_case ><#comment>拼接当前应用的请求路径</#comment>
    @RequestMapping(value="${appReqUrl}")
    public String hello(){
        return  String.format("您好,您目前正在访问[%s]实体","${de.codeName}");
    }
}

```


## 发布模板

您在iBizSys模板工具编写模板后，模板处于暂存状态，若您需要在项目中应用该模板，需要发布该模板。

![produce](img/quickstart/publishFtl.png)

## 发布模型

发布模型的过程即为从模板仓库中获取最新模板合成模型，生产代码的过程。

![produce](img/quickstart/publishSystem.png)

## 查看最终成果物

### 依赖

![produce](img/quickstart/result_pom.png)

### web配置

![produce](img/quickstart/result_webxml.png)

### SpringMVC配置

![produce](img/quickstart/result_springmvc.png)


### Spring配置

![produce](img/quickstart/result_spring.png)

### Controller

![produce](img/quickstart/result_controller.png)


添加测试类，进行功能测试，测试类相关代码如下：

```java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:ibizsys-dispatcher-servlet.xml","classpath:applicationContext.xml"})
@WebAppConfiguration
public class ApplicationTest {

    private MockMvc mockMvc;
    @Autowired
    protected WebApplicationContext wac;
    @Before
    public void beforeTest() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }
    @Test
    public void testMain() {
        try {
            MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/demo/springmvc/dbet")).andReturn();
            System.out.println("----正在调用实体controller----");
            System.out.println(String.format("返回内容为[%s]",mvcResult.getResponse().getContentAsString()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

```

控制台输出：

```
----正在调用实体controller----
返回内容为["您好,您目前正在访问[DBET]实体"]
 
```

## 小结

通过以上几个简单的步骤，您已经成功搭建一个SpringMVC项目，并为每个应用实体发布对应的Controller实现了能接收并响应用户请求的功能。并且您也成功了搭建了一套属于您个人的技术模板，您可以在以后的任何项目当中，使用您搭建的这套技术模板。

iBizSys可以帮助您快速搭建并使用您所搭建的技术模板来生产您的项目，想要了解更多iBizSys模板生产体系？那就继续往下看吧！



## 实体服务对象

通过第一章的学习，您已经成功搭建了一个SpringMVC项目，通过Controller来接收并响应用户请求。但在我们实际项目当中，Controller往往仅作为控制层，只负责转发用户的请求到Service，实际的业务是由Service层来处理的。本章就为大家演示通过模板发布服务层代码。


以下示例中将以`表单`的`增`、`删`、`改`、`查` 为例进行演示：

### Controller

Controller层为实体所用到的部件发布对应的restful接口，并调用Service进行处理 `本示例中仅以表单为例进行演示，仅发布出表单对应的行为接口`

```java

@RestController
public class ${de.codeName}Controller{

<#assign appReqUrl="/" +app.getPKGCodeName()?lower_case + "/"+de.getPSSystemModule().codeName?lower_case +"/"+de.codeName?lower_case ><#comment>当前实体请求路径</#comment>
<#comment>注入当前实体的服务对象</#comment>
    @Autowired
    private ${de.codeName}Service ${de.codeName?lower_case}Service;

<#list item.getPSControls() as ctrl><#comment>输出实体所使用到的部件（实体用到的部件可能有：表格、表单、树视图等）</#comment>
    <#if ctrl.getControlType() == 'FORM'><#comment>本示例中只展示表单</#comment>
        <#list ctrl.getPSAjaxControlHandler().getPSAjaxHandlerActions() as action><#comment>输出表单行为：(新建、编辑、删除等)</#comment>
        <#if action.getPSDEAction??  && action.getPSDEAction()??>
            <#assign ctrltype=ctrl.getControlType()>
    @PostMapping(value="${appReqUrl}/${ctrl.getCodeName()?lower_case}${srfclassname(ctrltype)?lower_case}/${action.getPSDEAction().getCodeName()?lower_case}")
    public ${de.codeName}  ${srfmethodname(ctrl.getCodeName())}${srfclassname(ctrltype)}${action.getPSDEAction().getCodeName()}(${de.codeName} entity){
        this.${de.codeName?lower_case}Service.${srfmethodname(action.getPSDEAction().getCodeName())}(entity);
            return entity;
    }
        </#if>
        </#list>
    </#if>
</#list>
}


```


### 服务接口

为每个实体发布服务接口 `%DE%Service.java.ftl`，service中发布该实体所有实体行为 `增`、`删`、`改`、`查`等

```java

/**
 * 实体[${item.codeName}] 服务对象接口
 */
public interface ${item.codeName}Service{

<#if item.getAllPSDEActions()??>
 <#list item.getAllPSDEActions() as deaction>
  <#if (deaction.getActionMode() == "READ") >
    ${item.codeName} ${srfmethodname(deaction.getCodeName())}(${item.codeName} et);
  <#else>
	boolean ${srfmethodname(deaction.getCodeName())}(${item.codeName} et);
  </#if>
 </#list>
</#if>

}


```


### 服务实现类

为每个实体发布服务实现类`%DE%ServiceImpl.java.ftl`，实现类中将对实体 `增`、`删`、`改`、`查` 等行为进行具体实现

```java

/**
 * 实体[${item.codeName}] 服务对象接口实现
 */
@Service
public class ${item.codeName}ServiceImpl  implements ${item.codeName}Service{

<#if item.getAllPSDEActions()??>
 <#list item.getAllPSDEActions() as deaction>
  <#if (deaction.getActionMode() == "READ") >
   @Override
   public ${item.codeName} ${srfmethodname(deaction.getCodeName())}(${item.codeName} et){
      System.out.println(String.format("您当前正在调用[%s]的[%s]方法","${item.codeName}ServiceImpl","${srfmethodname(deaction.getCodeName())}"));
      return  et;
   }
  <#else>
   @Override
   public boolean ${srfmethodname(deaction.getCodeName())}(${item.codeName} et){
      System.out.println(String.format("您当前正在调用[%s]的[%s]方法","${item.codeName}ServiceImpl","${srfmethodname(deaction.getCodeName())}"));
      return true;
   }
  </#if>
 </#list>
</#if>

}


```

### 实体类

循环输出所有实体属性

```java

/**
 * 实体[${item.codeName}] 数据对象
 */
@Data
public class ${item.codeName}{

<#list item.getPSDEFields() as defield>
    private ${srfjavatype(defield.stdDataType)} ${defield.codeName?lower_case};
</#list>

}


```

## 查看最终成果物

### Controller

![produce](img/service/result_controller.png)

### 服务接口

![produce](img/service/result_IService.png)

### 服务实现类

![produce](img/service/result_serviceImpl.png)

### 实体类

![produce](img/service/result_de.png)

### 开始使用


添加测试类，进行功能测试，测试类相关代码如下：

```java

@RunWith(SpringRunner.class)
@SpringMVCTest(classes = demoMain.class)
public class ApplicationTest {
    private MockMvc mockMvc;
    @Autowired
    private WebApplicationContext webApplicationContext;
    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }
    @Test
    public void contextLoads() {
        try {
            MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/demo/springmvc/dbet/maineditform/get")).andReturn();
            System.out.println("----正在调用实体controller----");
            System.out.println("返回结果为："+mvcResult.getResponse().getContentAsString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

```

控制台输出：

```
----正在调用实体controller----
您当前正在调用[DBETServiceImpl]的[get]方法
返回结果为：{"dbetname":null,"createdate":null,"createman":null,"dbetid":null,"updatedate":null,"updateman":null}
 
```


