让我们通过对Spring MVC的Controller开发的更多探索来改进以前的Spring JDBC应用程序 。 我将展示另一种编写新的Controller的练习,该Controller处理HTML表单并在JSP视图页面中使用JSTL标签。
要在Spring MVC应用程序中启用JSTL,您需要将以下内容添加到WebAppConfig
配置类中。 让我们将其移至WebApp.java
之外,并移至src/main/java/springweb/WebAppConfig.java
它自己的顶级类文件中。
package springweb;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan("springweb.controller")
public class WebAppConfig {
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver result = new InternalResourceViewResolver();
result.setPrefix("/");
result.setSuffix(".jsp");
return result;
}
}
在InternalResourceViewResolver
bean内,您定义在哪里可以找到其中包含JSTL标记的JSP页面。 prefix
设置器是相对于您的src/webapp
位置的路径。 如果需要,这可以让您完全隐藏JSP文件。 例如,通过将其设置为"/WEB-INF/jsp"
您可以将所有JSP文件移动并存储到src/webapp/WEB-INF/jsp
,该文件在Web应用程序中是私有的。 suffix
只是文件扩展名。 这两个值使您可以仅使用JSP文件的基本名称返回控制器内的视图名称,该名称可以缩写为“ / myform”或“ / index”等。
如果要将Tomcat用作Web容器,则还需要添加JSTL jar依赖项,因为Tomcat服务器不附带标准标记库! 因此,现在将其添加到pom.xml
文件中。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
当您使用pom.xml
文件时,可能要添加Tomcat maven插件,以便在运行Web应用程序时可以在命令行中键入更少的内容。
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
</plugin>
</plugins>
</build>
...
</project>
这样,您应该可以在项目的根目录下运行mvn tomcat7:run
而不使用插件前缀。
那么JSTL给您的应用带来了什么? 好吧,实际上很多。 它使您可以使用编写JSP视图时经常使用的一些标准JSP标记。 我将通过一组Controller和视图来演示这一点,以捕获来自应用程序的用户评论。 请注意,我将尝试仅以最基本的方式向您展示如何使用Spring Controller。 Spring实际上带有一个自定义form
JSP标记,该标记使用起来功能强大得多。 我将在其他时间将其保留为另一篇文章。 今天,让我们集中精力学习更多有关基本Spring Controller和JSTL的知识,以及有关Spring JDBC数据服务的更多知识。
我们想要捕获用户评论,因此让我们添加一个数据库表来存储该信息。 将以下DDL添加到src/main/resources/schema.sql
文件中。 同样,这是针对上一篇文章项目设置的H2数据库。
CREATE TABLE COMMENT (
ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
TEXT VARCHAR(10240) NOT NULL,
FROM_USER VARCHAR(15) NULL,
FROM_USER_IP VARCHAR(15) NULL,
FROM_URL VARCHAR(1024) NULL,
TAG VARCHAR(1024) NULL,
TS DATETIME NOT NULL
);
这次,我们将编写一个数据模型类来匹配该表。 让我们添加src/main/java/springweb/data/Comment.java
package springweb.data;
import java.util.Date;
public class Comment {
Long id;
String text;
String fromUrl;
String fromUser;
String fromUserIp;
String tag;
Date ts;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getFromUrl() {
return fromUrl;
}
public void setFromUrl(String fromUrl) {
this.fromUrl = fromUrl;
}
public String getFromUser() {
return fromUser;
}
public void setFromUser(String fromUser) {
this.fromUser = fromUser;
}
public String getFromUserIp() {
return fromUserIp;
}
public void setFromUserIp(String fromUserIp) {
this.fromUserIp = fromUserIp;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public Date getTs() {
return ts;
}
public void setTs(Date ts) {
this.ts = ts;
}
private String getTrimedComment(int maxLen) {
if (text == null)
return null;
if (text.length() <= maxLen)
return text;
return text.substring(0, maxLen);
}
@Override
public String toString() {
return "Comment{" +
"id=" + id +
", ts=" + ts +
", text='" + getTrimedComment(12) + '\'' +
'}';
}
public static Comment create(String commentText) {
Comment result = new Comment();
result.setText(commentText);
result.setTs(new Date());
return result;
}
}
就像以前的文章一样,我们将编写一个数据服务来处理数据模型的插入和检索。 我们添加一个新的src/main/java/springweb/data/CommentService.java
文件
package springweb.data;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Repository
public class CommentService {
public static Log LOG = LogFactory.getLog(CommentService.class);
private JdbcTemplate jdbcTemplate;
private SimpleJdbcInsert insertActor;
private RowMapper<Comment> commentBeanRowMapper = new BeanPropertyRowMapper<Comment>(Comment.class);
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.insertActor = new SimpleJdbcInsert(dataSource)
.withTableName("COMMENT")
.usingGeneratedKeyColumns("ID");
}
public void insert(Comment comment) {
LOG.info("Inserting Comment + " + comment);
Map<String, Object> parameters = new HashMap<String, Object>(2);
parameters.put("TEXT", comment.getText());
parameters.put("FROM_USER", comment.getFromUser());
parameters.put("FROM_USER_IP", comment.getFromUserIp());
parameters.put("FROM_URL", comment.getFromUrl());
parameters.put("TAG", comment.getTag());
parameters.put("TS", comment.getTs());
Number newId = insertActor.executeAndReturnKey(parameters);
comment.setId(newId.longValue());
LOG.info("New Comment inserted. Id=" + comment.getId());
}
public List<Comment> findComments() {
String sql = "SELECT " +
"ID as id, " +
"TEXT as text, " +
"TAG as tag, " +
"TS as ts, " +
"FROM_USER as fromUser, " +
"FROM_USER_IP as fromUserIp, " +
"FROM_URL as fromUrl " +
"FROM COMMENT ORDER BY TS";
List<Comment> result = jdbcTemplate.query(sql, commentBeanRowMapper);
LOG.info("Found " + result.size() + " Comment records.");
return result;
}
}
由于我们没有使用任何花哨的ORM,而只是使用普通的JDBC,因此我们将不得不在数据服务中编写SQL。 但是多亏了Spring的好东西,它使诸如SimpleJdbcInsert
助手使工作变得更加轻松,该助手处理数据库的插入和自动生成键的检索等。并且还要注意,在查询中,我们使用Spring的BeanPropertyRowMapper
将JDBC结果集自动转换为Java bean Comment
对象! 简单,直接,快速。
现在我们在src/main/java/springweb/controller/CommentController.java
添加Spring控制器来处理Web请求。
package springweb.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import springweb.data.Comment;
import springweb.data.CommentService;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Controller
public class CommentController {
@Autowired
private CommentService commentService;
@RequestMapping(value="/comments")
public ModelAndView comments() {
List<Comment> comments = commentService.findComments();
ModelAndView result = new ModelAndView("/comments");
result.addObject("comments", comments);
return result;
}
@RequestMapping(value="/comment")
public String comment() {
return "comment";
}
@RequestMapping(value="/comment", method = RequestMethod.POST)
public ModelAndView postComment(HttpServletRequest req, @RequestParam String commentText) {
String fromUrl = req.getRequestURI();
String user = req.getRemoteUser();
String userIp = req.getRemoteAddr();
Comment comment = Comment.create(commentText);
comment.setFromUserIp(userIp);
comment.setFromUser(user);
comment.setFromUrl(fromUrl);
commentService.insert(comment);
ModelAndView result = new ModelAndView("comment-posted");
result.addObject("comment", comment);
return result;
}
}
在此控制器中,我们映射/comment
URL来处理HTML表单的显示,该表单返回comment.jsp
视图。 该方法默认处理HTTP GET
。 请注意,我们在单独的postComment()
方法上重新映射了相同的/comment
URL来处理HTTP POST
! 在此演示中了解Spring Controller可以处理HTTP请求的干净程度。 非常注意postComment()
方法中声明的参数。 Spring会根据声明的类型自动处理HTTP请求对象并映射到您的方法! 在某些情况下,您需要借助@RequestParam
之类的注释来使其明确,但是Spring会为您解析HTTP请求和提取! 如果我们要编写直接的Servlet代码,则可以节省大量重复的样板代码。
现在让我们看一下视图以及如何使用JSTL。 /comments
URL映射到src/main/webapp/comments.jsp
视图文件,该文件将列出所有Comment
模型对象。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:choose>
<c:when test="${empty comments}">
<p>There are no comments in system yet.</p>
</c:when>
<c:otherwise>
<table border="1">
<tr>
<td>INDEX</td>
<td>TIME</td>
<td>FROM</td>
<td>COMMENT</td>
</tr>
<c:forEach items="${comments}" var="comment" varStatus="status">
<tr valign="top">
<td>${status.index}</td>
<td>${comment.ts}</td>
<td>${comment.fromUserIp}</td>
<%-- The c:out will escape html/xml characters. --%>
<td><pre><c:out value="${comment.text}"/></pre></td>
</tr>
</c:forEach>
</table>
</c:otherwise>
</c:choose>
JSTL上的相当标准的东西。 接下来是HTML表单,用于在src/main/webapp/comment.jsp
文件中发布评论。
<form action="comment" method="POST">
<textarea name="commentText" rows="20" cols="80"></textarea>
<br/>
<input type="submit" value="Post"/>
</form>
成功发布和处理表单后,我们只需返回src/main/webapp/comment-posted.jsp
文件中的新页面作为输出。
<p>Your comment has been posted. Comment ID=${comment.id}</p>
如果您已正确完成这些操作,则应该可以运行mvn tomcat7:run
并浏览http://localhost:8080/spring-web-annotation/comment
以查看表单。 转到/comments
URL以验证所有已发布的评论。
请注意,尽管我使用Spring Controller作为后端,但所有视图都在基本的JSTL中,甚至表单也只是基本HTML元素! 我这样做是为了让您看到Spring Controller有多灵活。
我知道今天有很多代码要发布到博客文章中,但是我想完整些,并尝试显示带有教程笔记的有效演示。 我选择将其包含在文件内容中,而不是将项目下载到其他地方。 它使我的注释和解释更易于与代码匹配。
到此为止,我们今天的教程结束了。 如果您觉得有帮助,请留下笔记。
翻译自: https://www.javacodegeeks.com/2013/10/exploring-spring-controller-with-jstl-view.html