This commit is contained in:
Seun Matt 2018-04-05 19:29:42 +01:00
commit 9f55d1a64d
18 changed files with 1538 additions and 8 deletions

View File

@ -0,0 +1,202 @@
package com.baeldung.rxjava.filters;
import org.junit.Test;
import rx.Observable;
import rx.observers.TestSubscriber;
public class RxJavaFilterOperatorsTest {
@Test
public void givenRangeObservable_whenFilteringItems_thenOddItemsAreFiltered() {
Observable<Integer> sourceObservable = Observable.range(1, 10);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.filter(i -> i % 2 != 0);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(5);
subscriber.assertValues(1, 3, 5, 7, 9);
}
@Test
public void givenRangeObservable_whenFilteringWithTake_thenOnlyFirstThreeItemsAreEmitted() {
Observable<Integer> sourceObservable = Observable.range(1, 10);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.take(3);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(3);
subscriber.assertValues(1, 2, 3);
}
@Test
public void givenObservable_whenFilteringWithTakeWhile_thenItemsEmittedUntilConditionIsVerified() {
Observable<Integer> sourceObservable = Observable.just(1, 2, 3, 4, 3, 2, 1);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.takeWhile(i -> i < 4);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(3);
subscriber.assertValues(1, 2, 3);
}
@Test
public void givenRangeObservable_whenFilteringWithTakeFirst_thenOnlyFirstItemIsEmitted() {
Observable<Integer> sourceObservable = Observable.just(1, 2, 3, 4, 5, 7, 6);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.takeFirst(x -> x > 5);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(1);
subscriber.assertValue(7);
}
@Test
public void givenRangeObservable_whenFilteringWithFirst_thenOnlyFirstThreeItemsAreEmitted() {
Observable<Integer> sourceObservable = Observable.range(1, 10);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.first();
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(1);
subscriber.assertValue(1);
}
@Test
public void givenEmptyObservable_whenFilteringWithFirstOrDefault_thenDefaultValue() {
Observable<Integer> sourceObservable = Observable.empty();
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.firstOrDefault(-1);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(1);
subscriber.assertValue(-1);
}
@Test
public void givenRangeObservable_whenFilteringWithTakeLast_thenLastThreeItemAreEmitted() {
Observable<Integer> sourceObservable = Observable.range(1, 10);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.takeLast(3);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(3);
subscriber.assertValues(8, 9, 10);
}
@Test
public void givenRangeObservable_whenFilteringWithLast_thenOnlyLastItemIsEmitted() {
Observable<Integer> sourceObservable = Observable.range(1, 10);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.last(i -> i % 2 != 0);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(1);
subscriber.assertValue(9);
}
@Test
public void givenRangeObservable_whenFilteringWithLastAndDefault_thenOnlyDefaultIsEmitted() {
Observable<Integer> sourceObservable = Observable.range(1, 10);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.lastOrDefault(-1, i -> i > 10);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(1);
subscriber.assertValue(-1);
}
@Test
public void givenObservable_whenTakingElementAt_thenItemAtSpecifiedIndexIsEmitted() {
Observable<Integer> sourceObservable = Observable.just(1, 2, 3, 5, 7, 11);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.elementAt(4);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(1);
subscriber.assertValue(7);
}
@Test
public void givenObservable_whenTakingElementAtOrDefault_thenDefaultIsReturned() {
Observable<Integer> sourceObservable = Observable.just(1, 2, 3, 5, 7, 11);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.elementAtOrDefault(7, -1);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(1);
subscriber.assertValue(-1);
}
@Test
public void givenMixedTypeObservable_whenFilteringByType_thenOnlyNumbersAreEmitted() {
Observable sourceObservable = Observable.just(1, "two", 3, "five", 7, 11);
TestSubscriber subscriber = new TestSubscriber();
Observable filteredObservable = sourceObservable.ofType(String.class);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(2);
subscriber.assertValues("two", "five");
}
}

View File

@ -0,0 +1,105 @@
package com.baeldung.rxjava.filters;
import org.junit.Test;
import rx.Observable;
import rx.observers.TestSubscriber;
public class RxJavaSkipOperatorsTest {
@Test
public void givenRangeObservable_whenSkipping_thenFirstFourItemsAreSkipped() {
Observable<Integer> sourceObservable = Observable.range(1, 10);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.skip(4);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(6);
subscriber.assertValues(5, 6, 7, 8, 9, 10);
}
@Test
public void givenObservable_whenSkippingWhile_thenFirstItemsAreSkipped() {
Observable<Integer> sourceObservable = Observable.just(1, 2, 3, 4, 5, 4, 3, 2, 1);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.skipWhile(i -> i < 4);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(6);
subscriber.assertValues(4, 5, 4, 3, 2, 1);
}
@Test
public void givenRangeObservable_whenSkippingLast_thenLastFiveItemsAreSkipped() {
Observable<Integer> sourceObservable = Observable.range(1, 10);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = sourceObservable.skipLast(5);
filteredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(5);
subscriber.assertValues(1, 2, 3, 4, 5);
}
@Test
public void givenObservable_whenFilteringDistinct_thenOnlyDistinctValuesAreEmitted() {
Observable<Integer> sourceObservable = Observable.just(1, 1, 2, 2, 1, 3, 3, 1);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> distinctObservable = sourceObservable.distinct();
distinctObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(3);
subscriber.assertValues(1, 2, 3);
}
@Test
public void givenObservable_whenFilteringDistinctUntilChanged_thenOnlyDistinctConsecutiveItemsAreEmitted() {
Observable<Integer> sourceObservable = Observable.just(1, 1, 2, 2, 1, 3, 3, 1);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> distinctObservable = sourceObservable.distinctUntilChanged();
distinctObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(5);
subscriber.assertValues(1, 2, 1, 3, 1);
}
@Test
public void givenRangeObservable_whenIgnoringElements_thenOnlyDistinctConsecutiveItemsAreEmitted() {
Observable<Integer> sourceObservable = Observable.range(1, 10);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> ignoredObservable = sourceObservable.ignoreElements();
ignoredObservable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(0);
subscriber.assertNoValues();
}
}

View File

@ -0,0 +1,221 @@
package com.baeldung.rxjava.filters;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.Test;
import rx.Observable;
import rx.observers.TestSubscriber;
import rx.schedulers.TestScheduler;
public class RxJavaTimeFilteringOperatorsTest {
@Test
public void givenTimedObservable_whenSampling_thenOnlySampleItemsAreEmitted() {
TestScheduler testScheduler = new TestScheduler();
Observable<Integer> timedObservable =
Observable.just(1, 2, 3, 4, 5, 6)
.zipWith(
Observable.interval(0, 1, TimeUnit.SECONDS, testScheduler),
(item, time) -> item
);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> sampledObservable =
timedObservable.sample(2500L, TimeUnit.MILLISECONDS, testScheduler);
sampledObservable.subscribe(subscriber);
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValues(3, 5, 6);
}
@Test
public void givenTimedObservable_whenThrottlingLast_thenThrottleLastItemsAreEmitted() {
TestScheduler testScheduler = new TestScheduler();
Observable<Integer> timedObservable =
Observable.just(1, 2, 3, 4, 5, 6)
.zipWith(
Observable.interval(0, 1, TimeUnit.SECONDS, testScheduler),
(item, time) -> item
);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = timedObservable.throttleLast(3100L, TimeUnit.MILLISECONDS, testScheduler);
filteredObservable.subscribe(subscriber);
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValues(4, 6);
}
@Test
public void givenRangeObservable_whenThrottlingFirst_thenThrottledFirstItemsAreEmitted() {
TestScheduler testScheduler = new TestScheduler();
Observable<Integer> timedObservable =
Observable.just(1, 2, 3, 4, 5, 6)
.zipWith(
Observable.interval(0, 1, TimeUnit.SECONDS, testScheduler),
(item, time) -> item
);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable =
timedObservable.throttleFirst(4100L, TimeUnit.MILLISECONDS, testScheduler);
filteredObservable.subscribe(subscriber);
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValues(1, 6);
}
@Test
public void givenTimedObservable_whenThrottlingWithTimeout_thenLastItemIsEmitted() {
TestScheduler testScheduler = new TestScheduler();
Observable<Integer> timedObservable =
Observable.just(1, 2, 3, 4, 5, 6)
.zipWith(
Observable.interval(0, 1, TimeUnit.SECONDS, testScheduler),
(item, time) -> item
);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = timedObservable.throttleWithTimeout(2000L, TimeUnit.MILLISECONDS, testScheduler);
filteredObservable.subscribe(subscriber);
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValue(6);
}
@Test
public void givenTimedObservable_whenDebounceOperatorIsApplied_thenLastItemIsEmitted() {
TestScheduler testScheduler = new TestScheduler();
Observable<Integer> timedObservable =
Observable.just(1, 2, 3, 4, 5, 6)
.zipWith(
Observable.interval(0, 1, TimeUnit.SECONDS, testScheduler),
(item, time) -> item
);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = timedObservable.debounce(2000L, TimeUnit.MILLISECONDS, testScheduler);
filteredObservable.subscribe(subscriber);
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValue(6);
}
@Test
public void givenTimedObservable_whenUsingTimeout_thenTimeOutException() {
TestScheduler testScheduler = new TestScheduler();
Observable<Integer> timedObservable =
Observable.just(1, 2, 3, 4, 5, 6)
.zipWith(
Observable.interval(0, 1, TimeUnit.SECONDS, testScheduler),
(item, time) -> item
);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = timedObservable.timeout(500L, TimeUnit.MILLISECONDS, testScheduler);
filteredObservable.subscribe(subscriber);
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS);
subscriber.assertError(TimeoutException.class);
subscriber.assertValues(1);
}
@Test
public void givenObservable_whenSkippingUntil_thenItemsAreSkippedUntilSecondObservableEmitsItems() {
TestScheduler testScheduler = new TestScheduler();
Observable<Integer> timedObservable =
Observable.just(1, 2, 3, 4, 5, 6)
.zipWith(
Observable.interval(0, 1, TimeUnit.SECONDS, testScheduler),
(item, time) -> item
);
Observable<Integer> delayedObservable = Observable.just(1)
.delay(3000, TimeUnit.MILLISECONDS, testScheduler);
TestSubscriber<Integer> subscriber = new TestSubscriber();
Observable<Integer> filteredObservable = timedObservable.skipUntil(delayedObservable);
filteredObservable.subscribe(subscriber);
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValues(4, 5, 6);
}
@Test
public void givenObservable_whenSkippingWhile_thenItemsAreEmittedUntilSecondObservableEmitsItems() {
TestScheduler testScheduler = new TestScheduler();
Observable<Integer> timedObservable =
Observable.just(1, 2, 3, 4, 5, 6)
.zipWith(
Observable.interval(0, 1, TimeUnit.SECONDS, testScheduler),
(item, time) -> item
);
TestSubscriber subscriber = new TestSubscriber();
Observable<Integer> delayedObservable = Observable.just(1)
.delay(3000, TimeUnit.MILLISECONDS, testScheduler);
Observable<Integer> filteredObservable = timedObservable.takeUntil(delayedObservable);
filteredObservable.subscribe(subscriber);
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValues(1, 2, 3);
}
}

View File

@ -15,3 +15,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Geolocation by IP in Java](http://www.baeldung.com/geolocation-by-ip-with-maxmind)
- [Guide to JavaServer Pages (JSP)](http://www.baeldung.com/jsp)
- [Exploring SpringMVCs Form Tag Library](http://www.baeldung.com/spring-mvc-form-tags)
- [Guide to JSTL](http://www.baeldung.com/guide-to-jstl)

View File

@ -37,6 +37,13 @@
<!-- web -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
@ -57,6 +64,13 @@
<version>${hibernate-validator.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<!-- Json conversion -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@ -108,6 +122,14 @@
</build>
<repositories>
<repository>
<id>1</id>
<name>jstl</name>
<url>https://mvnrepository.com/artifact/javax.servlet/jstl</url>
</repository>
</repositories>
<properties>
<!-- Spring -->
<org.springframework.version>5.0.2.RELEASE</org.springframework.version>

View File

@ -0,0 +1,17 @@
package com.baeldung.jstl.bundles;
import java.util.ListResourceBundle;
public class CustomMessage_en extends ListResourceBundle {
@Override
protected Object[][] getContents() {
return contents;
}
static final Object[][] contents = {
{"verb.go", "go"},
{"verb.come", "come"},
{"verb.sit", "sit"},
{"verb.stand", "stand"}
};
}

View File

@ -0,0 +1,17 @@
package com.baeldung.jstl.bundles;
import java.util.ListResourceBundle;
public class CustomMessage_fr_FR extends ListResourceBundle {
@Override
protected Object[][] getContents() {
return contents;
}
static final Object[][] contents = {
{"verb.go", "aller"},
{"verb.come", "venir"},
{"verb.sit", "siéger"},
{"verb.stand", "se lever"}
};
}

View File

@ -0,0 +1,125 @@
package com.baeldung.jstl.controllers;
import com.baeldung.jstl.dbaccess.SQLConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.sql.*;
import java.util.Calendar;
@Controller
public class JSTLController {
private static final Logger LOGGER = LoggerFactory.getLogger(JSTLController.class.getName());
@Autowired
ServletContext servletContext;
@PostConstruct
public void init() {
PreparedStatement preparedStatement = null;
Connection connection = null;
try {
connection = SQLConnection.getConnection();
preparedStatement = connection.prepareStatement("create table IF NOT EXISTS USERS " +
"( id int not null primary key AUTO_INCREMENT," +
" email VARCHAR(255) not null, first_name varchar (255), last_name varchar (255), registered DATE)");
int status = preparedStatement.executeUpdate();
preparedStatement = connection.prepareStatement("SELECT COUNT(*) AS total FROM USERS;");
ResultSet result = preparedStatement.executeQuery();
if(result!=null) {
result.next();
if (result.getInt("total") == 0) {
generateDummy(connection);
}
} else {
generateDummy(connection);
}
} catch (Exception e) {
LOGGER.error(e.getMessage());
} finally {
try {
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
LOGGER.error(e.getMessage());
}
}
}
@RequestMapping(value = "/core_tags", method = RequestMethod.GET)
public ModelAndView coreTags(final Model model) {
ModelAndView mv = new ModelAndView("core_tags");
return mv;
}
@RequestMapping(value = "/core_tags_redirect", method = RequestMethod.GET)
public ModelAndView coreTagsRedirect(final Model model) {
ModelAndView mv = new ModelAndView("core_tags_redirect");
return mv;
}
@RequestMapping(value = "/formatting_tags", method = RequestMethod.GET)
public ModelAndView formattingTags(final Model model) {
ModelAndView mv = new ModelAndView("formatting_tags");
return mv;
}
@RequestMapping(value = "/sql_tags", method = RequestMethod.GET)
public ModelAndView sqlTags(final Model model) {
ModelAndView mv = new ModelAndView("sql_tags");
return mv;
}
@RequestMapping(value = "/xml_tags", method = RequestMethod.GET)
public ModelAndView xmlTags(final Model model) {
ModelAndView mv = new ModelAndView("xml_tags");
return mv;
}
@RequestMapping(value = "/items_xml", method = RequestMethod.GET)
@ResponseBody public FileSystemResource getFile(HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/xml");
return new FileSystemResource(new File(servletContext.getRealPath("/WEB-INF/items.xsl")));
}
@RequestMapping(value = "/function_tags", method = RequestMethod.GET)
public ModelAndView functionTags(final Model model) {
ModelAndView mv = new ModelAndView("function_tags");
return mv;
}
private void generateDummy(Connection connection) throws SQLException {
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO USERS " +
"(email, first_name, last_name, registered) VALUES (?, ?, ?, ?);");
preparedStatement.setString(1, "patrick@baeldung.com");
preparedStatement.setString(2, "Patrick");
preparedStatement.setString(3, "Frank");
preparedStatement.setDate(4, new Date(Calendar.getInstance().getTimeInMillis()));
preparedStatement.addBatch();
preparedStatement.setString(1, "bfrank@baeldung.com");
preparedStatement.setString(2, "Benjamin");
preparedStatement.setString(3, "Franklin");
preparedStatement.setDate(4, new Date(Calendar.getInstance().getTimeInMillis()));
preparedStatement.executeBatch();
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.jstl.dbaccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class SQLConnection {
private static String userName = "root";
private static String password = "";
private static final Logger LOGGER = LoggerFactory.getLogger(SQLConnection.class.getName());
public static Connection getConnection() throws Exception {
LOGGER.error("connecting...");
Class.forName("com.mysql.cj.jdbc.Driver");
LOGGER.error("class checked...");
Connection conn = null;
Properties connectionProps = new Properties();
connectionProps.put("user", userName);
connectionProps.put("password", password);
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test?autoReconnect=true&useSSL=false",
connectionProps);
LOGGER.info("Connected to database");
return conn;
}
}

View File

@ -23,7 +23,7 @@
</mvc:message-converters>
</mvc:annotation-driven>
<context:component-scan base-package="com.baeldung.spring.controller"/>
<context:component-scan base-package="com.baeldung.spring.controller, com.baeldung.jstl.controllers"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>

View File

@ -0,0 +1,27 @@
<?xml version = "1.0"?>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0">
<xsl:output method = "html" indent = "yes"/>
<xsl:param name = "bgColor"/>
<xsl:template match = "/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match = "items">
<table border = "1" width = "40%" bgColor = "{$bgColor}">
<xsl:for-each select = "item">
<tr>
<td><i><xsl:value-of select = "name"/></i></td>
<td><xsl:value-of select = "category"/></td>
<td><xsl:value-of select = "price"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>

View File

@ -7,7 +7,7 @@
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.baeldung.spring.controller"/>
<context:component-scan base-package="com.baeldung.spring.controller, com.baeldung.jstl.controllers"/>
<!-- Start: Mapping by bean name (BeanNameUrlHandlerMapping) -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
@ -40,12 +40,6 @@
<bean id="helloController" class="com.baeldung.spring.controller.HelloController"/>
<!-- End: Mapping by SimpleUrlHandlerMapping -->
<!-- Start: Mapping by ControllerClassNameHandlerMapping -->
<bean
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
<property name="caseSensitive" value="true"/>
<property name="order" value="0"/>
</bean>
<bean class="com.baeldung.spring.controller.HelloGuestController"/>
<!-- End: Mapping by ControllerClassNameHandlerMapping -->

View File

@ -0,0 +1,92 @@
<%@ page import="java.util.Random" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.Calendar" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<c:set value="JSTL Core Tags Example" var="pageTitle"/>
<title>
<c:out value="${pageTitle}"/>
</title>
</head>
<body>
<h1>
<c:out value="${pageTitle}"/>
</h1>
<c:remove var="pageTitle"/>
<p><c:out value="${pageTitle}"/></p>
<div>
<h3>
<c:out value="<c:catch> Example"/>
</h3>
<c:catch var ="exceptionThrown">
<% int x = Integer.valueOf("a");%>
</c:catch>
<c:if test = "${exceptionThrown != null}">
<p>The exception is : ${exceptionThrown} <br />
There is an exception: ${exceptionThrown.message}</p>
</c:if>
</div>
<div>
<h3>
<c:out value="<c:choose> Example"/>
<c:set value="<%= Calendar.getInstance().get(Calendar.SECOND)%>" var="seconds"/>
</h3>
<p>
<c:choose>
<c:when test="${seconds le 30 }">
<c:out value="${seconds} is less than 30"/>
</c:when>
<c:when test="${seconds eq 30 }">
<c:out value="${seconds} is equal to 30"/>
</c:when>
<c:otherwise>
<c:out value="${seconds} is greater than 30"/>
</c:otherwise>
</c:choose>
</p>
</div>
<div>
<h3>
<c:out value="<c:import> Example"/>
</h3>
<c:import var = "data" url = "http://www.example.com"/>
<c:out value = "${data}"/>
</div>
<div>
<h3>
<c:out value="<c:forEach> Example"/>
</h3>
<c:forEach var = "i" items="1,4,5,6,7,8,9">
Item <c:out value = "No. ${i}"/><p>
</c:forEach>
</div>
<div>
<h3>
<c:out value="<c:forToken> Example"/>
</h3>
<c:forTokens items = "Patrick:Wilson:Ibrahima:Chris" delims = ":" var = "name">
<c:out value = "Name: ${name}"/><p>
</c:forTokens>
</div>
<div>
<h3>
<c:out value="<c:url> and <c:param> Example"/>
</h3>
<c:url value = "/core_tags" var = "myURL">
<c:param name = "parameter_1" value = "1234"/>
<c:param name = "parameter_2" value = "abcd"/>
</c:url>
<c:out value = "URL: ${myURL}"/>
</div>
</body>
</html>

View File

@ -0,0 +1,16 @@
<%@ page import="java.util.Random" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.Calendar" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<c:set value="JSTL Core Tags Examples" var="pageTitle"/>
<title>
<c:out value="${pageTitle}"/>
</title>
</head>
<body>
<c:redirect url="/core_tags"/>
</body>
</html>

View File

@ -0,0 +1,213 @@
<%@ page import="java.util.Calendar" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<c:set value="JSTL Formatting Tags Example" var="pageTitle"/>
<title>
<c:out value="${pageTitle}"/>
</title>
</head>
<body>
<h1>
<c:out value="${pageTitle}"/>
</h1>
<div>
<h3>
<c:out value="<fmt:formatNumber> Example"/>
</h3>
<c:set var="fee" value="35050.1067"/>
<p>Formatted Number - Currency: <fmt:formatNumber value="${fee}"
type="currency"/></p>
<p>Formatted Number - Maximum Integer Digits: <fmt:formatNumber type="number"
maxIntegerDigits="2" value="${fee}"/></p>
<p>Formatted Number - Maximum Fraction Digits: <fmt:formatNumber type="number"
maxFractionDigits="2" value="${fee}"/></p>
<p>Formatted Number - Grouping: <fmt:formatNumber type="number"
groupingUsed="false" value="${fee}"/></p>
<p>Formatted Number - Percent with Maximum Integer Digits: <fmt:formatNumber type="percent"
maxIntegerDigits="3"
value="${fee}"/></p>
<p>Formatted Number - Percent with Minimum Fraction Digits: <fmt:formatNumber type="percent"
minFractionDigits="10"
value="${fee}"/></p>
<p>Formatted Number Percent with Minimum Integer Digits: <fmt:formatNumber type="percent"
minIntegerDigits="4" value="${fee}"/></p>
<p>Formatted Number - with Pattern: <fmt:formatNumber type="number"
pattern="###.##E0" value="${fee}"/></p>
<p>Formatted Number - Currency with Internationalization :
<fmt:setLocale value="en_US"/>
<fmt:formatNumber value="${fee}" type="currency"/>
</p>
</div>
<div>
<h3>
<c:out value="<fmt:parseNumber> Example"/>
</h3>
<fmt:parseNumber var="i" type="number" value="${fee}"/>
<p>Parsed Number : <c:out value="${i}"/></p>
<fmt:parseNumber var="i" integerOnly="true"
type="number" value="${fee}"/>
<p>Parsed Number - with Integer Only set to True: <c:out value="${i}"/></p>
</div>
<div>
<h3>
<c:out value="<fmt:formatDate> Example"/>
<c:set var="now" value="<%= new java.util.Date()%>"/>
</h3>
<p>Formatted Date - with type set to time: <fmt:formatDate type="time"
value="${now}"/></p>
<p>Formatted Date - with type set to date: <fmt:formatDate type="date"
value="${now}"/></p>
<p>Formatted Date - with type set to both: <fmt:formatDate type="both"
value="${now}"/></p>
<p>Formatted Date - with short style for both date and time: <fmt:formatDate type="both"
dateStyle="short" timeStyle="short"
value="${now}"/></p>
<p>Formatted Date - with medium style for both date and time: <fmt:formatDate type="both"
dateStyle="medium" timeStyle="medium"
value="${now}"/></p>
<p>Formatted Date - with long style for both date and time: <fmt:formatDate type="both"
dateStyle="long" timeStyle="long"
value="${now}"/></p>
<p>Formatted Date - with pattern: <fmt:formatDate pattern="yyyy-MM-dd"
value="${now}"/></p>
</div>
<div>
<h3>
<c:out value="<fmt:parseDate> Example"/>
</h3>
<c:set var="today" value="28-03-2018"/>
<fmt:parseDate value="${today}" var="parsedDate" pattern="dd-MM-yyyy"/>
<p>Parsed Date: <c:out value="${parsedDate}"/></p>
</div>
<div>
<h3>
<c:out value="<fmt:bundle> and <fmt:message> Example"/>
</h3>
<p>
<fmt:bundle basename="com.baeldung.jstl.bundles.CustomMessage" prefix="verb.">
<fmt:message key="go"/><br/>
<fmt:message key="come"/><br/>
<fmt:message key="sit"/><br/>
<fmt:message key="stand"/><br/>
</fmt:bundle>
</p>
</div>
<div>
<h3>
<c:out value="<fmt:setLocale> Example"/>
</h3>
<p>
<fmt:setLocale value="fr_FR"/>
<fmt:bundle basename="com.baeldung.jstl.bundles.CustomMessage" prefix="verb.">
<fmt:message key="go"/><br/>
<fmt:message key="come"/><br/>
<fmt:message key="sit"/><br/>
<fmt:message key="stand"/><br/>
</fmt:bundle>
</p>
</div>
<div>
<h3>
<c:out value="<fmt:setBundle> Example"/>
</h3>
<p>
<fmt:setLocale value="En"/>
<fmt:setBundle basename="com.baeldung.jstl.bundles.CustomMessage" var="lang"/>
<fmt:message key="verb.go" bundle="${lang}"/><br/>
<fmt:message key="verb.come" bundle="${lang}"/><br/>
<fmt:message key="verb.sit" bundle="${lang}"/><br/>
<fmt:message key="verb.stand" bundle="${lang}"/><br/>
</p>
</div>
<div>
<h3>
<c:out value="<fmt:timeZone> Example"/>
</h3>
<table border="1" width="40%">
<tr>
<td width="100%" colspan="2">
<p align="center">
<b>
<font size="4">Time being formatted:
<fmt:formatDate value="${now}" type="both"
timeStyle="long" dateStyle="long"/>
</font>
</b>
</p>
</td>
</tr>
<c:forEach var="zone"
items="<%= java.util.TimeZone.getAvailableIDs()%>" end="4">
<tr>
<td width="51%">
<c:out value="${zone}"/>
</td>
<td width="49%">
<fmt:timeZone value="${zone}">
<fmt:formatDate value="${now}" timeZone="${zn}"
type="both"/>
</fmt:timeZone>
</td>
</tr>
</c:forEach>
</table>
</div>
<div>
<h3>
<c:out value="<fmt:setTimeZone> Example"/>
</h3>
<p>Current Date with Default Time Zone: <fmt:formatDate value="${now}"
type="both" timeStyle="long" dateStyle="long"/></p>
<p>Change Time Zone to GMT+9</p>
<fmt:setTimeZone value="GMT+9"/>
<p>Date in Changed Zone: <fmt:formatDate value="${now}"
type="both" timeStyle="long" dateStyle="long"/></p>
</div>
<div>
<h3>
<c:out value="<fmt:requestEncoding> Example"/>
</h3>
<fmt:requestEncoding value = "UTF-8" />
<fmt:setLocale value = "fr_FR"/>
<fmt:setBundle basename = "com.baeldung.jstl.bundles.CustomMessage" var = "lang"/>
<fmt:message key="verb.go" bundle="${lang}"/><br/>
<fmt:message key="verb.come" bundle="${lang}"/><br/>
<fmt:message key="verb.sit" bundle="${lang}"/><br/>
<fmt:message key="verb.stand" bundle="${lang}"/><br/>
</div>
</body>
</html>

View File

@ -0,0 +1,151 @@
<%@ page import="java.util.Random" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.Calendar" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix = "fn"
uri = "http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
<c:set value="JSTL Function Tags Example" var="pageTitle"/>
<title>
<c:out value="${pageTitle}"/>
</title>
</head>
<body>
<h1>
<c:out value="${pageTitle}"/>
</h1>
<c:set var = "string1" value = "This is first string"/>
<c:set var = "string2" value = "This is second string with <tag>test XML</tag>"/>
<div>
<h3>
<c:out value="fn:contains() Example"/>
</h3>
<c:if test = "${fn:contains(string1, 'first')}">
<p>Found 'first' in string<p>
</c:if>
</div>
<div>
<h3>
<c:out value="fn:containsIgnoreCase() Example"/>
</h3>
<c:if test = "${fn:containsIgnoreCase(string1, 'first')}">
<p>Found 'first' string<p>
</c:if>
<c:if test = "${fn:containsIgnoreCase(string1, 'FIRST')}">
<p>Found 'FIRST' string<p>
</c:if>
</div>
<div>
<h3>
<c:out value="fn:endsWith() Example"/>
</h3>
<c:if test = "${fn:endsWith(string1, 'string')}">
<p>String ends with 'string'<p>
</c:if>
</div>
<div>
<h3>
<c:out value="fn:escapeXml() Example"/>
</h3>
<p>With escapeXml() Function:</p>
<p>string (1) : ${fn:escapeXml(string1)}</p>
<p>string (2) : ${fn:escapeXml(string2)}</p>
<p>Without escapeXml() Function:</p>
<p>string (1) : ${string1}</p>
<p>string (2) : ${string2}</p>
</div>
<div>
<h3>
<c:out value="fn:indexOf() Example"/>
</h3>
<p>Index (1) : ${fn:indexOf(string1, "first")}</p>
<p>Index (2) : ${fn:indexOf(string2, "second")}</p>
</div>
<div>
<h3>
<c:out value="fn:join() and fn:split() Example"/>
</h3>
<c:set var = "string3" value = "${fn:split(string1, ' ')}" />
<c:set var = "string4" value = "${fn:join(string3, '-')}" />
<p>Final String : ${string4}</p>
</div>
<div>
<h3>
<c:out value="fn:length() Example"/>
</h3>
<p>Length of String (1) : ${fn:length(string1)}</p>
<p>Length of String (2) : ${fn:length(string2)}</p>
</div>
<div>
<h3>
<c:out value="fn:replace() Example"/>
</h3>
<c:set var = "string3" value = "${fn:replace(string1, 'first', 'third')}" />
<p>Final String : ${string3}</p>
</div>
<div>
<h3>
<c:out value="fn:startsWith() Example"/>
</h3>
<c:if test = "${fn:startsWith(string1, 'This')}">
<p>String starts with 'This'</p>
</c:if>
</div>
<div>
<h3>
<c:out value="fn:substring() Example"/>
</h3>
<c:set var = "string3" value = "${fn:substring(string1, 5, 15)}" />
<p>Final sub string : ${string3}</p>
</div>
<div>
<h3>
<c:out value="fn:substringAfter() Example"/>
</h3>
<c:set var = "string3" value = "${fn:substringAfter(string1, 'is')}" />
<p>Final sub string : ${string3}</p>
</div>
<div>
<h3>
<c:out value="fn:substringBefore() Example"/>
</h3>
<c:set var = "string3" value = "${fn:substringBefore(string1, 'is')}" />
<p>Final sub string : ${string3}</p>
</div>
<div>
<h3>
<c:out value="fn:toLowerCase() Example"/>
</h3>
<c:set var = "string3" value = "${fn:toLowerCase(string1)}" />
<p>Final string : ${string3}</p>
</div>
<div>
<h3>
<c:out value="fn:toUpperCase() Example"/>
</h3>
<c:set var = "string3" value = "${fn:toUpperCase(string1)}" />
<p>Final string : ${string3}</p>
</div>
<div>
<h3>
<c:out value="fn:trim() Example"/>
</h3>
<c:set var = "string1" value = "This is first String "/>
<p>String (1) Length : ${fn:length(string1)}</p>
<c:set var = "string2" value = "${fn:trim(string1)}" />
<p>String (2) Length : ${fn:length(string2)}</p>
<p>Final string : "${string2}"</p>
</div>
</body>
</html>

View File

@ -0,0 +1,198 @@
<%@ page import="java.util.Random" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.Calendar" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
<html>
<head>
<c:set value="JSTL SQL Tags Example" var="pageTitle"/>
<title>
<c:out value="${pageTitle}"/>
</title>
</head>
<body>
<h1>
<c:out value="${pageTitle}"/>
</h1>
<!--
sql:setDataSource Example
-->
<sql:setDataSource var="dataSource" driver="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost/test"
user="root" password=""/>
<div>
<h3>
<c:out value="<sql:query> Example"/>
</h3>
<sql:query dataSource="${dataSource}" var="result">
SELECT * from USERS;
</sql:query>
<table border="1" width="50%">
<tr>
<th>User ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Registered</th>
</tr>
<c:forEach var="user" items="${result.rows}" varStatus="iterator">
<tr>
<td><c:out value="${iterator.index + 1}"/></td>
<td><c:out value="${user.first_name}"/></td>
<td><c:out value="${user.last_name}"/></td>
<td><c:out value="${user.email}"/></td>
<td><c:out value="${user.registered}"/></td>
</tr>
</c:forEach>
</table>
</div>
<div>
<h3>
<c:out value="<sql:update> Example"/>
</h3>
<sql:update dataSource="${dataSource}" var="count">
INSERT INTO USERS(first_name, last_name, email) VALUES ('Grace', 'Adams', 'gracea@domain.com');
</sql:update>
<sql:query dataSource="${dataSource}" var="result">
SELECT * from USERS;
</sql:query>
<table border="1" width="50%">
<tr>
<th>User ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Registered</th>
</tr>
<c:forEach var="user" items="${result.rows}" varStatus="iterator">
<tr>
<td><c:out value="${iterator.index + 1}"/></td>
<td><c:out value="${user.first_name}"/></td>
<td><c:out value="${user.last_name}"/></td>
<td><c:out value="${user.email}"/></td>
<td><c:out value="${user.registered}"/></td>
</tr>
</c:forEach>
</table>
</div>
<div>
<h3>
<c:out value="<sql:param> Example"/>
</h3>
<sql:update dataSource = "${dataSource}" var = "count">
DELETE FROM USERS WHERE email = ?
<sql:param value = "gracea@domain.com" />
</sql:update>
<sql:query dataSource="${dataSource}" var="result">
SELECT * from USERS;
</sql:query>
<table border="1" width="50%">
<tr>
<th>User ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Registered</th>
</tr>
<c:forEach var="user" items="${result.rows}" varStatus="iterator">
<tr>
<td><c:out value="${iterator.index + 1}"/></td>
<td><c:out value="${user.first_name}"/></td>
<td><c:out value="${user.last_name}"/></td>
<td><c:out value="${user.email}"/></td>
<td><c:out value="${user.registered}"/></td>
</tr>
</c:forEach>
</table>
</div>
<div>
<h3>
<c:out value="<sql:dateParam> Example"/>
</h3>
<%
Date registered = new Date("2018/03/31");
String email = "patrick@baeldung.com";
%>
<sql:update dataSource = "${dataSource}" var = "count">
UPDATE Users SET registered = ? WHERE email = ?
<sql:dateParam value = "<%=registered%>" type = "DATE" />
<sql:param value = "<%=email%>" />
</sql:update>
<sql:query dataSource="${dataSource}" var="result">
SELECT * from USERS;
</sql:query>
<table border="1" width="50%">
<tr>
<th>User ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Registered</th>
</tr>
<c:forEach var="user" items="${result.rows}" varStatus="iterator">
<tr>
<td><c:out value="${iterator.index + 1}"/></td>
<td><c:out value="${user.first_name}"/></td>
<td><c:out value="${user.last_name}"/></td>
<td><c:out value="${user.email}"/></td>
<td><c:out value="${user.registered}"/></td>
</tr>
</c:forEach>
</table>
</div>
<div>
<h3>
<c:out value="<sql:transaction> Example"/>
</h3>
<sql:transaction dataSource = "${dataSource}">
<sql:update var = "count">
UPDATE Users SET first_name = 'Patrick-Ellis' WHERE email='patrick@baeldung.com'
</sql:update>
<sql:update var = "count">
UPDATE Users SET last_name = 'Nelson' WHERE email = 'patrick@baeldung.com'
</sql:update>
<sql:update var = "count">
INSERT INTO Users(first_name, last_name, email) VALUES ('Grace', 'Adams', 'gracea@domain.com');
</sql:update>
</sql:transaction>
<sql:query dataSource="${dataSource}" var="result">
SELECT * from USERS;
</sql:query>
<table border="1" width="50%">
<tr>
<th>User ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Registered</th>
</tr>
<c:forEach var="user" items="${result.rows}" varStatus="iterator">
<tr>
<td><c:out value="${iterator.index + 1}"/></td>
<td><c:out value="${user.first_name}"/></td>
<td><c:out value="${user.last_name}"/></td>
<td><c:out value="${user.email}"/></td>
<td><c:out value="${user.registered}"/></td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>

View File

@ -0,0 +1,99 @@
<%@ page import="java.util.Random" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.Calendar" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
<html>
<head>
<c:set value="JSTL XML Tags Example" var="pageTitle"/>
<title>
<c:out value="${pageTitle}"/>
</title>
</head>
<body>
<h1>
<c:out value="${pageTitle}"/>
</h1>
<c:remove var="pageTitle"/>
<p><c:out value="${pageTitle}"/></p>
<div>
<h3>
<c:out value="<x:transform>, <x::param>, <x:parse>, <x:set>, <x:out>, and <x:if> Examples"/>
</h3>
<h3>Store Items:</h3>
<c:set var="xmltext">
<items>
<item>
<name>Steve Madden</name>
<category>Sneakers</category>
<price>34</price>
</item>
<item>
<name>Pearl Izumi</name>
<category>Sneakers</category>
<price>80</price>
</item>
<item>
<name>Katy Perry</name>
<category>Heels</category>
<price>72</price>
</item>
</items>
</c:set>
<x:parse xml="${xmltext}" var="output"/>
<b>The name of the first item listed in the store is</b>:
<x:out select="$output/items/item[1]/name"/> with price $<x:out select="$output/items/item[1]/price"/>
<br>
<x:set var="fragment" select="$output//item"/>
<b>The second item is </b>:
<c:out value="${fragment}"/>
<x:if select="$output//item">
Document has at least one
<item> element.
</x:if>
<br/>
<c:import url="/items_xml" var="xslt"/>
<x:transform xml="${xmltext}" xslt="${xslt}">
<x:param name="bgColor" value="blue"/>
</x:transform>
</div>
<div>
<h3>
<c:out value="<x:forEach> Example"/>
</h3>
<ul class="items">
<x:forEach select="$output/items/item/name" var="item">
<li>Item Name: <x:out select="$item"/></li>
</x:forEach>
</ul>
</div>
<div>
<h3>
<c:out value="<x:choose>, <x:when> and <x:otherwise> Example"/>
</h3>
<x:choose>
<x:when select="$output//item/category = 'Sneakers'">
Item category is Sneakers
</x:when>
<x:when select="$output//item/category = 'Heels'">
Item category is Heels
</x:when>
<x:otherwise>
Unknown category.
</x:otherwise>
</x:choose>
</div>
</body>
</html>