#124 - Added sample for Querydsl integration.

Move web project to web/example and add web/querydsl as a dedicated one demonstrating the QueryDSL Predicate usage in Spring MVC.
This commit is contained in:
Christoph Strobl
2015-07-20 16:12:27 +02:00
committed by Oliver Gierke
parent a999bed747
commit 97eefb0afc
32 changed files with 3159 additions and 57 deletions

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.users;
import lombok.Value;
/**
* @author Christoph Strobl
*/
@Value
public class Address {
private String city;
private String street;
private String zip;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.users;
import lombok.Value;
/**
* @author Christoph Strobl
*/
@Value
public class Picture {
private String large;
private String medium;
private String small;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.users;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
/**
* @author Christoph Strobl
*/
@Data
@Document
public class User {
@Id private String username;
private String firstname;
private String lastname;
private String email;
private String nationality;
@JsonIgnore private String password;
@JsonUnwrapped private Address address;
private Picture picture;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.users;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import example.users.UserInitializer.Datasource;
/**
* @author Christoph Strobl
*/
@SpringBootApplication
public class UserApp {
@Autowired UserRepository repo;
public static void main(String[] args) {
SpringApplication.run(UserApp.class, args);
}
@PostConstruct
void initialize() throws Exception {
new UserInitializer(repo).init(100, Datasource.LOCAL);
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.users;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.separator.DefaultRecordSeparatorPolicy;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
/**
* @author Christoph Strobl
*/
public class UserInitializer {
private final UserRepository repository;
public enum Datasource {
LOCAL, REMOTE;
}
public UserInitializer(UserRepository repository) throws UnexpectedInputException, ParseException, Exception {
this.repository = repository;
}
private List<User> readUsers(Resource resource, int nrUsers) throws Exception {
Scanner scanner = new Scanner(resource.getInputStream());
String line = scanner.nextLine();
scanner.close();
FlatFileItemReader<User> reader = new FlatFileItemReader<User>();
reader.setResource(resource);
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
tokenizer.setNames(line.split(","));
tokenizer.setStrict(false);
DefaultLineMapper<User> lineMapper = new DefaultLineMapper<User>();
lineMapper.setFieldSetMapper(fields -> {
User user = new User();
user.setEmail(fields.readString("email"));
user.setFirstname(fields.readString("first"));
user.setLastname(fields.readString("last"));
user.setNationality(fields.readString("nationality"));
try {
user.setAddress(new Address(fields.readString("city"), fields.readString("street"), fields.readString("zip")));
} catch (IllegalArgumentException e) {
user.setAddress(new Address(fields.readString("city"), fields.readString("street"), fields
.readString("postcode")));
}
user.setPicture(new Picture(fields.readString("large"), fields.readString("medium"), fields
.readString("thumbnail")));
user.setUsername(fields.readString("username"));
user.setPassword(fields.readString("password"));
return user;
});
lineMapper.setLineTokenizer(tokenizer);
reader.setLineMapper(lineMapper);
reader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy());
reader.setLinesToSkip(1);
reader.open(new ExecutionContext());
List<User> users = new ArrayList<>();
User user = null;
int count = 0;
do {
user = reader.read();
if (user != null) {
users.add(user);
}
} while (user != null && ++count < nrUsers);
return users;
}
public void init(int nrUsers, Datasource source) throws Exception {
if (repository.count() != nrUsers) {
Resource resource = Datasource.LOCAL.equals(source) ? new ClassPathResource("randomuser.me.csv")
: new UrlResource("https://randomuser.me/api/?results=" + nrUsers + "&format=csv");
List<User> users = readUsers(resource, nrUsers);
if (!users.isEmpty()) {
repository.deleteAll();
repository.save(users);
}
}
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.users;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
import org.springframework.data.querydsl.binding.QuerydslBindings;
import org.springframework.data.repository.CrudRepository;
import com.mysema.query.types.path.StringPath;
/**
* @author Christoph Strobl
*/
public interface UserRepository extends CrudRepository<User, String>, QueryDslPredicateExecutor<User>,
QuerydslBinderCustomizer<QUser> {
@Override
default public void customize(QuerydslBindings bindings, QUser root) {
bindings.bind(String.class).first((StringPath path, String value) -> path.containsIgnoreCase(value));
bindings.excluding(root.password);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.users;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
/**
* @author Christoph Strobl
*/
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webjars/**").//
addResourceLocations("classpath:/META-INF/resources/webjars/").//
resourceChain(true);
}
@Bean
public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
return new ResourceUrlEncodingFilter();
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.users.web;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.querydsl.QuerydslPredicate;
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 com.mysema.query.types.Predicate;
import example.users.User;
import example.users.UserRepository;
/**
* @author Christoph Strobl
*/
@Controller
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserController {
private final UserRepository repository;
@RequestMapping(value = "/", method = RequestMethod.GET)
String index(Model model, @QuerydslPredicate(root = User.class) Predicate predicate, Pageable pageable) {
model.addAttribute("users", repository.findAll(predicate, pageable));
return "index";
}
}