关闭

[置顶] SpringMVC+Maven开发最小“自然语言理解”项目攻略(附源码打包下载及详细说明)

标签: javaspring mvcolamimaven智能语义解析
1128人阅读 评论(0) 收藏 举报
分类:

Spring MVC概述

Spring MVC框架是一个开源的Java平台,为开发强大的基于Java的Web应用程序提供全面的基础架构支持非常容易和非常快速。

Spring web MVC框架提供了MVC(模型 - 视图 - 控制器)架构和用于开发灵活和松散耦合的Web应用程序的组件。

MVC模式导致应用程序的不同方面(输入逻辑,业务逻辑和UI逻辑)分离,同时提供这些元素之间的松散耦合。

  • 模型(Model)封装了应用程序数据,通常它们将由POJO类组成。

  • 视图(View)负责渲染模型数据,一般来说它生成客户端浏览器可以解释HTML输出。

  • 控制器(Controller)负责处理用户请求并构建适当的模型,并将其传递给视图进行渲染。

项目源码详细介绍

该项目实现了智能解析用户输入语句的语义,输出结果以JSON格式展示。
源码下载:SpringMVCDemoNLI

1、 创建目录结构

创建一个Maven工程为:SpringMVCDemoNLI。下图为最终的目录结构:

2、 配置pom.xml

<?xml version="1.0"?>
<project
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
    xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.demo</groupId>
    <artifactId>SpringMVCDemoNLI</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringMVCDemoNLI Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <springframework.version>4.0.6.RELEASE</springframework.version>
        <hibernate.validator.version>5.1.2.Final</hibernate.validator.version>
        <javax.validation.version>1.1.0.Final</javax.validation.version>

        <!-- 主要依赖库的版本定义 -->
        <httpclient.version>4.5.3</httpclient.version>
        <commons-lang3.version>3.5</commons-lang3.version>
        <commons-codec.version>1.10</commons-codec.version>
        <commons-logging.version>1.2</commons-logging.version>
        <httpcore.version>4.4.6</httpcore.version>
        <taglibs-standard.version>1.2.5</taglibs-standard.version>
        <fastjson.version>1.2.34</fastjson.version>

    </properties>
    <dependencies>
        <!-- Spring dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springframework.version}</version>
        </dependency>

        <!-- httpclient -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>${commons-codec.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons-lang3.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>${commons-logging.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>${httpcore.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>${httpclient.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>${httpclient.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>

        <!-- jsr303 validation dependencies -->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>${javax.validation.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>${hibernate.validator.version}</version>
        </dependency>

        <!-- Servlet dependencies -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

    <build>
        <defaultGoal>compile</defaultGoal>
        <pluginManagement>
            <plugins>               
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.7</source>
                        <target>1.7</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <finalName>SpringMVCDemoNLI</finalName>
    </build>
</project>

3、创建POJO/域对象

保存用户提交的数据,并使用验证注释验证属性。

package com.demo.model;

import java.io.Serializable;
import javax.validation.constraints.Size;

public class CorpusInfo implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Size(min=2, max=30)
    private String corpus;

    public String getCorpus() {
        return corpus;
    }

    public void setCorpus(String corpus) {
        this.corpus = corpus;
    }

    @Override
    public String toString() {
        return "";
    }

}

4、添加控制器

控制器处理GET和POST请求。

@Controller表明这个类是一个控制器在处理具有模式映射的@RequestMapping请求。这里使用 ‘/’, 它被作为默认的控制器。

方法inputCorpus注解为RequestMethod.GET服务默认是GET请求,并呈现包含空白表单的网页。

方法nliProcess注解为RequestMethod.POST服务处理表单提交POST请求。

@Valid要求spring来验证相关的对象(CorpusInfo)。

package com.demo.controller;

import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.demo.model.CorpusInfo;
import com.demo.util.NLIProcess;


@Controller
@RequestMapping("/")
public class DemoController {

    private NLIProcess nli = new NLIProcess();

    @RequestMapping(method = RequestMethod.GET)
    public String inputCorpus(ModelMap model) {
        CorpusInfo cinfo = new CorpusInfo();
        model.addAttribute("cinfo", cinfo);
        return "enroll";
    }

    @RequestMapping(method=RequestMethod.POST)
    public String nliProcess(@Valid  @ModelAttribute("cinfo") CorpusInfo cinfo,
            BindingResult result, ModelMap model) {

        if (result.hasErrors()) {
            return "enroll";
        }
        model.addAttribute("answer", nli.getAnswer(cinfo.getCorpus()));
        return "success";
    }

}

nli.getAnswer(cinfo.getCorpus())实现语义解析,这里是使用的欧拉蜜开放平台智能语义解析

package com.demo.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;


public class NLIProcess {
    private static final String url = "https://cn.olami.ai/cloudservice/api";
    private static final String Appkey = "fcf20941682b494e9db8c23c14deeb74";
    private static final String Appsecret = "1bcbbe1fb5924185a13c9b5f6d548ee0";
    private static final String api = "nli";    

    private JSONObject process (String input) {
        JSONObject NLIresult = new JSONObject();
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("appkey", Appkey));
        params.add(new BasicNameValuePair("api", api));

        long timestamp = Calendar.getInstance().getTimeInMillis();
        params.add(new BasicNameValuePair("timestamp", String.valueOf(timestamp)));
        params.add(new BasicNameValuePair("sign", generateSign(timestamp)));

        JSONObject request = new JSONObject();
        JSONObject data = new JSONObject();
        try {
            data.put("input_type", 0);
            data.put("text", input);

            request.put("data_type", "stt");
            request.put("data", data);
        } catch (JSONException e1) {
            e1.printStackTrace();
            return NLIresult;
        }
        params.add(new BasicNameValuePair("rq", request.toString()));
        params.add(new BasicNameValuePair("cusid", "asdfghj"));

        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httppost = new HttpPost(url);
        try {
            httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httppost);
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String contnt = EntityUtils.toString(entity);
                    NLIresult = JSONObject.parseObject(contnt);
                }
            } finally {
                response.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return NLIresult;
        } finally {
            try {
                httpclient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return NLIresult;
    }

    private String generateSign(long timestamp) {
        String sign = Appsecret + "api=" + api + "appkey=" + Appkey + "timestamp=" + timestamp + Appsecret;
        return MD5String(sign);
    }

    public String MD5String(String str) {
        try {
            MessageDigest msgDigest = MessageDigest.getInstance("MD5");
            msgDigest.reset();
            msgDigest.update(str.getBytes("UTF-8"));
            byte[] byteArrary = msgDigest.digest();
            StringBuffer md5StrBuff = new StringBuffer();
            for (int i = 0; i < byteArrary.length; i++) {
                String tmp = Integer.toHexString(0xFF & byteArrary[i]);
                if (tmp.length() == 1) {
                    md5StrBuff.append(0).append(tmp);
                } else {
                    md5StrBuff.append(tmp);
                }
            }
            return md5StrBuff.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public String getAnswer(String corpus){
        if(corpus != null && !corpus.equals("")){
            JSONObject jsObj = process(corpus);
            return formatJson(jsObj);
        }
        return "请输入正确的语料!";
    }

    private static String appendJson(String str, int count) {
        String retStr = "<br>";
        for (int i = 0; i < count; i++) {
            retStr += str;
        }
        return retStr;
    }

    /**
     * 将json转成便于阅读的格式
     * @param oldJson
     * @return
     */
    public static String formatJson(JSONObject old) {
        int i = 0;
        String space = "&nbsp;&nbsp;";
        String formatJson = "";
        int indentCount = 0;
        Boolean isStr = false;
        String currChar = "";

        String oldJson = old.toString();

        for (i = 0; i < oldJson.length(); i++) {
            currChar = oldJson.substring(i, i + 1);
            switch (currChar) {
            case "{":
            case "[":
                if (!isStr) {
                    indentCount++;
                    formatJson += currChar + appendJson(space, indentCount);
                } else {
                    formatJson += currChar;
                }
                break;
            case "}":
            case "]":
                if (!isStr) {
                    indentCount--;
                    formatJson += appendJson(space, indentCount) + currChar;
                } else {
                    formatJson += currChar;
                }
                break;
            case ",":
                if (!isStr) {
                    formatJson += "," + appendJson(space, indentCount);
                } else {
                    formatJson += currChar;
                }
                break;
            case ":":
                if (!isStr) {
                    formatJson += ": ";
                } else {
                    formatJson += currChar;
                }
                break;
            case " ":
            case "\n":
            case "\t":
                if (isStr) {
                    formatJson += currChar;
                }
                break;
            case "\"":
                if (i > 0 && !oldJson.substring(i - 1, i).equals("\\")) {
                    isStr = !isStr;
                }
                formatJson += currChar;
                break;
            default:
                formatJson += currChar;
                break;
            }
        }
        return formatJson;
    }

}

5、添加配置类

@Configuration指示该类包含注解为@Bean生产Bean管理是由Spring容器的一个或多个 bean 的方法。

@EnableWebMvc 等效于 mvc:annotation-driven 在XML文件中。

@ComponentScan 等效于 context:component-scan base-package=”…” 提供具有到哪里查找管理Spring beans/类。

方法ViewResolver 配置一个 ViewResolver 用来找出真正的视图。

方法 addResourceHandlers 配置 ResourceHandler 静态资源。例子中,将css文件放在 Web应用程序的 /static/css 目录中。

package com.demo.configuration;

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.demo")
public class DemoConfiguration extends WebMvcConfigurerAdapter {

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages");
        return messageSource;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }
}

方法messageSource 配置消息包,以支持[国际化]消息属性文件。Spring 将搜索应用程序类路径中一个名为messages.properties文件:

Size.cinfo.corpus=corpus must be between {2} and {1} characters long

6、添加视图(JSP页面)

添加两个JSP页面。第一个将包含一个表单,从用户接收输入,第二个是当表单输入验证成功时会显示成功消息给用户。

WEB-INF/views/enroll.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=Utf-8">
<title>智能语义解析——基于欧拉蜜开放平台</title>
<link href="<c:url value='/static/css/custom.css' />" rel="stylesheet"></link>
</head>

<body>

    <div class="form-container">

        <h1>智能语义理解</h1>

        <form:form method="POST" modelAttribute="cinfo"
            class="form-horizontal">

            <div class="row">
                <label class="form-group col-md-1" for="corpus">输入语句:</label>
                <div class="form-group col-md-2">
                    <form:input type="text" path="corpus" id="corpus"
                        class="form-control input-sm" />
                        <div class="has-error">
                            <form:errors path="corpus" class="help-inline" />
                        </div>
                </div>
                <div class="form-group floatRight">
                    <input type="submit" value="send" class="btn btn-primary btn-sm">
                </div>
            </div>          

            <div class="row" style="color:#006600">
                <label class="form-group col-md-1" for="corpus"><br>目前支持的语义解析领域有以下六个模块:</label>
            </div>          

            <div class="row" style="color:#006600">
                <label class="form-group col-md-1" for="corpus">新闻:</label>
                <div class="form-group col-md-2">
                <br>
                    app:news<br>
                    语料示例:<br>
                    今天的新闻<br>
                    有哪些娱乐新闻<br>
                    我要看新闻 <br>
                    新闻头条<br>
                </div>
            </div>          

            <div class="row" style="color:#006600">
                <label class="form-group col-md-1" for="corpus">星座:</label>
                <div class="form-group col-md-2">
                <br>
                    app:horoname<br>
                    语料示例:<br>
                    天蝎座的运势<br>
                    天蝎座的本月运势<br>
                    帮我查查明日运势,天蝎座的<br>
                </div>
            </div>          

            <div class="row" style="color:#006600">
                <label class="form-group col-md-1" for="corpus">公交:</label>
                <div class="form-group col-md-2">
                <br>
                    app:busline<br>
                    语料示例:<br>
                    615路的行车路线<br>
                    112路有哪些站点<br>
                    张江南环线停靠哪些站<br>
                    110路的公交路线<br>
                </div>
            </div>          

            <div class="row" style="color:#006600">
                <label class="form-group col-md-1" for="corpus">成语:</label>
                <div class="form-group col-md-2">
                <br>
                    app:idioms<br>
                    语料示例:<br>
                    告诉我画龙点睛是什么意思<br>
                    画龙点睛的含义<br>
                    有没有哪个成语叫龙什么的<br>
                    带龙的成语有哪些<br>
                </div>
            </div>          

            <div class="row" style="color:#006600">
                <label class="form-group col-md-1" for="corpus">笑话:</label>
                <div class="form-group col-md-2">
                <br>
                    app:joke<br>
                    语料示例:<br>
                    讲笑话<br>
                    给我讲个笑话吧<br>
                    来张趣图<br>
                    我要看笑话<br>
                </div>
            </div>      

            <div class="row" style="color:#006600">
                <label class="form-group col-md-1" for="corpus">解梦:</label>
                <div class="form-group col-md-2">
                <br>
                    app:oneiromancy<br>
                    语料示例:<br>
                    给我查查梦到了黄金有什么寓意<br>
                    昨天做梦梦到黄金了<br>
                    梦到黄金了有什么说法<br>
                    我昨天做了一个关于黄金的梦<br>
                </div>
            </div>          

        </form:form>

    </div>
</body>
</html>

WEB-INF/views/success.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>智能语义解析——基于欧拉蜜开放平台</title>
<link href="<c:url value='/static/css/custom.css' />" rel="stylesheet"></link>
</head>
<body>
    <div class="success">
        <div style="color:#006600">
            news支持类别有:头条(importnews),娱乐(ent),体育(sports),军事(mil),金融(finance),财经(fortune),教育(edu),法治(fz),健康(health),社会(society)。<br>
            horoname支持查询的运势有:今日运势、明日运势、本周运势、本月运势、今年运势。<br> <br>
            app:模块名称。 <br> modifier:表示一句话的操作意图。 如语句 查看娱乐新闻 的意图为 查,
            即用“query”来表示。 <br> slot:表示需要从语料中提取出来的关键字。 如语句 查看娱乐新闻 的意图已知道是
            查,而查什么则是由slot来补充,即slot名字为type,值为从语料中提取出来的词语“娱乐”。<br>
            更多详细介绍可参考:
            <a href="https://cn.olami.ai/wiki/?mp=nli&content=nli_response_result.html">https://cn.olami.ai/wiki/?mp=nli&content=nli_response_result.html</a>
        </div>
        <br>
        <br> ${answer}
    </div>
</body>
</html>

static/css/custom.css

.form-container {
  position:fiexd;
  width:30%;
  margin-left: 20px;
  margin-top: 20px;
  margin-bottom: 20px;
  padding: 10px;
  background-color: #E8E1E1;
  border: 1px solid #ddd;
  border-radius: 4px;
}

  .form-group {
    display: inline-block;
    margin-bottom: 0;
    vertical-align: middle;
  }

.input-sm {
  width: 400px;
  height: 30px;
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 3px;
}

.floatRight{
    float:right;
    margin-right: 18px;
}

.row {
  margin-right: 15px;
  margin-left: 15px;
}

.col-md-1, .col-md-2 {
  position: relative;
  min-height: 1px;
  padding-right: 5px;
  padding-left: 5px;
}

.has-error{
    color:red;
}

.success{
  position:fiexd;
  width:50%;
  margin-left: 50px;
  margin-top:20px;
  padding: 20px;
  background-color: #E8E1E1;
  border: 1px solid #ddd;
  border-radius: 4px;
}

7、添加初始化器类

package com.demo.configuration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class DemoInitializer implements WebApplicationInitializer {

    public void onStartup(ServletContext container) throws ServletException {

        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(DemoConfiguration.class);
        ctx.setServletContext(container);

        ServletRegistration.Dynamic servlet = container.addServlet(
                "dispatcher", new DispatcherServlet(ctx));

        servlet.setLoadOnStartup(1);
        servlet.addMapping("/");
    }

}

8、构建和部署应用程序

运行应用程序,访问URL:http://localhost:8080/SpringMVCDemoNLI

得到的初始页面如下图所示:

提交不正确输入时,会得到验证错误(在 message.properties 中用户定义的消息)

提交成功后跳转页面如下:

2
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:5810次
    • 积分:156
    • 等级:
    • 排名:千里之外
    • 原创:8篇
    • 转载:0篇
    • 译文:0篇
    • 评论:9条