Давайте улучшим наше предыдущее Spring JDBC-приложение с дополнительным изучением разработки контроллеров Spring MVC. Я покажу еще одно упражнение по написанию нового контроллера, который обрабатывает HTML-форму и использует теги JSTL на страницах просмотра JSP.
Чтобы включить JSTL в приложении Spring MVC, вам нужно добавить следующее в WebAppConfig конфигурации WebAppConfig . Давайте переместим его за пределы WebApp.java и в его собственный файл класса верхнего уровня в src/main/java/springweb/WebAppConfig.java .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
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; }} |
Внутри bean-компонента InternalResourceViewResolver вы определяете, где найти страницы JSP, в которых могут быть теги JSTL. Установщик prefix — это путь относительно вашего местоположения src/webapp . Это позволяет полностью скрыть файлы JSP, если вы хотите. Например, установив его в "/WEB-INF/jsp" вы можете переместить и сохранить все файлы JSP в src/webapp/WEB-INF/jsp который является частным в веб-приложении. suffix — это просто расширение файла. Эти два значения позволяют вам возвращать имя представления внутри контроллера только с базовым именем вашего файла JSP, которое может быть коротким как «/ myform» или «/ index» и т. Д.
Если вы хотите использовать Tomcat в качестве веб-контейнера, вам также необходимо добавить JSTL-зависимость JAR, поскольку сервер Tomcat не поставляется со стандартной библиотекой тегов! Так что добавьте это в файл pom.xml сейчас.
|
1
2
3
4
5
|
<dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> |
Пока вы находитесь в файле pom.xml , вы можете добавить плагин Tomcat Maven, чтобы при запуске веб-приложения вы могли меньше вводить в командной строке.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<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. Я продемонстрирую это с помощью набора контроллеров и представлений для сбора комментариев пользователей из приложения. Обратите внимание, что я постараюсь показать вам, как работать с Spring Controller только самым простым способом. Spring на самом деле поставляется с пользовательским JSP-тегом form который гораздо более мощный в использовании. Я зарезервирую это как другую статью в другое время. Сегодня давайте сосредоточимся на том, чтобы больше узнать о базовом Spring Controller и JSTL, а также немного о сервисе данных Spring JDBC.
Мы хотим записать комментарии пользователей, поэтому давайте добавим таблицу базы данных для хранения этой информации. Добавьте следующий DDL в ваш файл src/main/resources/schema.sql . Опять же, это для базы данных H2 в последней настройке проекта статьи.
|
1
2
3
4
5
6
7
8
9
|
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
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
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
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
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;@Repositorypublic 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 в службе данных. Но благодаря положительным SimpleJdbcInsert Spring, это значительно облегчает жизнь с помощью таких помощников, как SimpleJdbcInsert , который обрабатывает вставку БД и извлечение автоматически сгенерированного ключа и т. Д. А также обратите внимание, что в запросе мы используем BeanPropertyRowMapper в Spring для автоматического преобразования BeanPropertyRowMapper JDBC в Java-бин. Comment объекта! Просто, прямо и быстро.
Теперь мы добавляем контроллер Spring в src/main/java/springweb/controller/CommentController.java для обработки веб-запросов.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
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;@Controllerpublic 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 . Обратите внимание, что мы переназначили один /comment тот же URL /comment URL /comment для обработки HTTP POST в отдельном postComment() ! Посмотрите, насколько чистым может быть Spring Controller в этой демонстрации для обработки HTTP-запроса. Обратите особое внимание на параметры, объявленные в postComment() . Spring автоматически обрабатывает объект HTTP-запроса и сопоставляет его с вашим методом только на основании объявленных вами типов! В некоторых случаях вы должны быть явными с помощью аннотации, такой как @RequestParam , но Spring выполняет анализ HTTP-запроса и извлечения за вас! Это сэкономит вам тонны повторяющегося кода котельной пластины, если мы напишем прямой код сервлета.
Теперь давайте посмотрим на представление и как использовать JSTL. URL-адрес /comments отображается в файл представления src/main/webapp/comments.jsp , в котором будут перечислены все объекты модели Comment .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<%@ 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 .
|
1
2
3
4
5
|
<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 качестве вывода.
|
1
|
<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.
Я знаю, что это много кода для публикации сегодня в блоге, но я хотел закончить и попытаться показать рабочую демонстрацию с примечаниями к учебнику. Я предпочитаю сделать его одним постом с содержимым файла, а не загружать проект где-то еще. Это облегчает сопоставление моих заметок и объяснений с кодом.
И это завершит наш урок на сегодня. Пожалуйста, оставьте записку, если вы найдете это полезным.