Spring MVC + separated front-end
Case study
Piotr Lewandowski
@piotlr
Back-end
- Java 8
- Spring 4 + Spring boot
- Apache POI
- Thymeleaf
- Gradle
Front-end
- bootstrap
- require.js
- npm
- bower
- gulp
Java 8
Java 7 way
Java 8 way
List<Human> humans = ...
Collections.sort(humans, new Comparator<Human>() {
@Override
public int compare(Human h1, Human h2)
return h1.getName().compareTo(h2.getName());
}
}
List<Human> humans = ...
Collections.sort(humans, (Human h1, Human h2) -> {
h1.getName().compareTo(h2.getName())
});
Streams API
List<Person> persons = ...;
Stream tenPersonsOver18 = persons.stream()
.filter(p -> p.getAge() > 18)
.limit(10);
boolean isEmptyRow = csvRowEntries.stream()
.allMatch(str -> str.isEmpty());
if (isEmptyRow) {
return null;
}
Streams API
// set id, location
employees.stream()
.filter(e -> e.getId().equals(id))
.findFirst()
.ifPresent(e -> {
e.setLocation(location);
});
public List<String> getErrors() {
return parseErrors.stream()
.map(pe -> pe.getMessage())
.collect(Collectors.toList());
}
Streams in tests
// arrange
// ...
List<MissingEmployee> divergenceReport;
List<String> missingEmployees;
// act
divergenceReport = service.getDivergenceReport();
missingEmployees = divergenceReport.stream()
.map(MissingEmployee::getId)
.collect(Collectors.toList());
// assert
assertThat(missingEmployees.contains("Robert Smith"), is(true));
Confusions
- Closure
- Custom lambdas
Closures
int i = 0;
persons.forEach(person -> {
if ( person == null) {
i++; // Error: Variable must be final or effective final
}
...
});
Custom lamdas
public class Main {
public static void runCalc( ??? calc) {
// ???
}
public static void main(String[] args) {
BigDecimal a = new BigDecimal();
runCalc(a -> a.multiply(a));
}
}
Custom lambdas
Scala
def runCalc(calc: (BigInt => BigInt)) {
// ...
}
Java
interface MyCalcLambda {
BigInteger run(BigInteger input);
}
public static void runCalc(MyCalcLambda calc) {
// ...
}
public static void main(String[] args) {
runCalc(a -> a.multiply(a));
}
Running custom lambdas
Scala
def runCalc(calc: (BigInt => BigInt)) {
System.out.println(calc(10))
}
Java
public static void runCalc(MyCalcLambda calc) {
System.out.println(calc(BigInteger.TEN));
}
Spring 4
with Spring boot
Long story short
Configuration
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
start.spring.io
Thymeleaf
- Primitive
- Maps
- Lists
- i18n config constans
- loops
- conditionals
- formats
- modules
What can we put?
What can we do?
<div th:replace="fragments/header :: header"> </div>
<table>
<thead>
<tr>
<th th:text="#{project.name}">Name</th>
<th th:text="#{project.cost}">Cost</th>
<th th:text="#{project.hours}">Hours</th>
</tr>
</thead>
<tbody>
<tr th:each="project : ${projects}">
<td th:text="${project.projectId}">Project ID</td>
<td th:text="${#numbers.formatDecimal(project.salary, 1, 'COMMA', 2, 'POINT')}">
1000.0
</td>
<td th:text="${#numbers.formatDecimal(project.hours, 1, 'COMMA', 2, 'POINT')}">
353
</td>
</tr>
</tbody>
</table>
HTML5 way
<table>
<!--/*/ <th-block data-th-each="user : ${users}"> /*/-->
<tr>
<td data-th-text="${user.login}">...</td>
<td data-th-text="${user.name}">...</td>
</tr>
<tr>
<td data-th-text="${user.address}">...</td>
</tr>
<!--/*/ </th-block> /*/-->
</table>
Gradle
Worries
- Do I need to learn groovy?
- Can I still use my dependencies?
- If my IDE supports gradle?
gradle hello world
apply plugin: 'java'
sourceCompatibility = 1.8
jar {
baseName = 'demo'
version = '0.0.1-SNAPSHOT'
}
repositories {
mavenCentral()
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
repositories {
maven {
credentials {
username 'user'
password 'password'
}
url "http://10.10.0.1/your-maven-repo"
}
}
Custom repostiories
So why gradle?
- Clean
- Efficient
- Easily expandable with plugins
Front-end
Building front-end
- Modularity
- Dependency managment
- Production-ready
- Tests
Cons
- Many, many tools
- Frequent changes
Pros
- Many, many tools
- Frequent changes
Front-end structure
src
├── css
├── js
dist
├── lib
├── css
├── js
gulpfile.js
bower.json
package.json
Build tools demo
Building process
What are doing when we type `gradle build`
gradle build
- Compille front-end
- Download tools with NPM
- Download dependencies with bower
- Build front-end with gulp
- Pack into JAR
- Compile the rest with front-end as a dependency
Thanks
Java 8 + Spring boot
By Piotr Lewandowski
Java 8 + Spring boot
Case study
- 662