Lunch and Learn

May 6, 2015
Reid Harrison
- Apache Struts -> Spring MVC
- Gin & Guice and Spring
- Security
- JDBC
- Android
- Social
- OAuth2
- XD
- Batch
- Integration
- Data
- Test
2013
Personal Mobile Project
2014
Unified Presentation Framework
2010
Georgia Tech Research Institute
2012
Personal Web Project
My Spring History
"Spring helps development teams everywhere build simple, portable,
fast and flexible JVM-based systems and applications."

Rod Johnson

Juergen Hoeller


Mark Pollack
Mark Fisher
What is Spring?


-
Spring Documentation
- Dense but detailed
- Often hard to understand
-
Tutorials
- Often outdated
- Use in conjunction with docs and other tuts
-
Examples
- Good starting point
- Numerous but simple
-
Exploration
- Figure it out for yourself
- Become familiar with internals
Learning Spring

@Repository
public class PeopleDao extends JdbcDaoSupport {
@InjectLogger
private Logger logger;
@Inject
public PeopleDao(final DataSource dataSource) {
setDataSource(dataSource);
}
}
@Configuration
public class SpringConfig {
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/tdpapp");
dataSource.setUsername("username");
dataSource.setPassword("password");
return dataSource;
}
}Spring Dependency Injection

@Controller
public class HelloController {
@RequestMapping(value = "/")
public ModelAndView home() {
ModelAndView mav = new ModelAndView("index");
String greeting = "Hello, World!";
mav.addObject("greeting", greeting);
return mav;
}
@RequestMapping(value = "helloWorld", method = RequestMethod.GET)
public @ResponseBody
String helloWorld(final String greeting) {
if ("Hello!".equals(greeting)) {
return "Hello, World!";
}
return "Hell no, World!";
}
}Spring MVC

@Target({ METHOD, CONSTRUCTOR, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Inject {}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CurrentUser { }public class ActiveUserWebArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
Annotation[] paramAnns = methodParameter.getParameterAnnotations();
for (Annotation paramAnn : paramAnns) {
if (CurrentUser.class.isInstance(paramAnn)) {
return true;
}
}
return false;
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
Principal principal = nativeWebRequest.getUserPrincipal();
if (principal == null) {
return null;
}
User springUser = (User) ((Authentication) principal).getPrincipal();
}
}Java Annotations

Java Annotations
@Controller
public class AppController {
@RequestMapping("getNotificationCount")
public int getNotificationCount(@CurrentUser User currentUser) {
return service.getUserNotificationCount(currentUser.getUsername());
}
}
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Inject
private DataSource userDataSource;
@Override
public void configure(AuthenticationManagerBuilder authBuilder) throws Exception {
authBuilder
.jdbcAuthentication()
.dataSource(userDataSource)
.usersByUsernameQuery(USER_BY_USERNAME_QUERY)
.authoritiesByUsernameQuery(AUTHORITIES_BY_USERNAME_QUERY);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/css/**", "/img/**", "/js/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("index").permitAll()
.loginProcessingUrl("login").permitAll()
.successHandler(new CustomAuthenticationSuccessHandler())
.failureHandler(new CustomAuthenticationFailureHandler())
.and()
.logout()
.logoutUrl("logout")
.logoutSuccessUrl("index").permitAll();
}
}Spring Security

@Controller
public class AppController {
@Secured({"ADMIN"})
@RequestMapping(value="admin")
public String admin() {
return "admin";
}
@PreAuthorize("#username == authentication.name")
@RequestMapping(value="u/{username}/edit", method=RequestMethod.GET)
public ModelAndView editUser(@PathVariable String username) {
ModelAndView mav = new ModelAndView("editUser");
mav.addObject("user", service.getUserInfo(username);
return mav;
}
}
Spring Security
@Repository
public class PeopleDao extends JdbcDaoSupport {
@Inject
public PeopleDao(final DataSource dataSource) {
setDataSource(dataSource);
}
. . .
public List<Expertise> getExpertise(final String eid) {
return getJdbcTemplate().query(SELECT_PERSON_EXPERTISE_SQL, new String[] { eid }, new PeopleRowMappers.ExpertiseRowMapper());
}
public Integer createExpertise(final String newExpertiseName) {
//Construct a SimpleJdbcInsert so that the new expertise's key can be returned from the database
SimpleJdbcInsert insert = new SimpleJdbcInsert(getJdbcTemplate())
.withTableName("expertise")
.usingColumns("name")
.usingGeneratedKeyColumns("id");
Map<String, Object> expertiseValues = new TreeMap<String, Object>();
expertiseValues.put("name", newExpertiseName);
//Execute the insert and capture the returned primary key
final Number newExpertiseKey = insert.executeAndReturnKey(expertiseValues);
if (newExpertiseKey == null) {
throw new IllegalStateException("New expertise's primary key was not returned by database after insertion, " +
"the new expertise will not be able to be related to a person.");
}
final int newExpertiseId = newExpertiseKey.intValue();
return newExpertiseId;
}
}Spring JDBC

public void updatePersonSchool(final String eid, final Integer schoolId) {
getJdbcTemplate().update(UPDATE_PERSON_SCHOOL_SQL, new PreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
if (schoolId != null) {
ps.setInt(1, schoolId);
} else {
ps.setNull(1, Types.INTEGER);
}
ps.setString(2, eid);
}
});
}
Spring JDBC
@Controller
public class TwitterFriendsController {
private final Twitter twitter;
@Inject
public TwitterFriendsController(Twitter twitter) {
this.twitter = twitter;
}
@RequestMapping(value="/twitter/friends", method=RequestMethod.GET)
public String friends(Model model) {
model.addAttribute("profiles", twitter.friendOperations().getFriends());
return "twitter/friends";
}
@RequestMapping(value="/twitter/followers", method=RequestMethod.GET)
public String followers(Model model) {
model.addAttribute("profiles", twitter.friendOperations().getFollowers());
return "twitter/friends";
}
}Spring Social

Spring Social
@Configuration
@EnableSocial
public class SocialConfig implements SocialConfigurer {
@Override
public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig, Environment env) {
cfConfig.addConnectionFactory(new TwitterConnectionFactory(
env.getProperty("twitter.consumerKey"),
env.getProperty("twitter.consumerSecret")));
}
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public Twitter twitter(ConnectionRepository repository) {
Connection<Twitter> connection = repository.findPrimaryConnection(Twitter.class);
return connection != null ? connection.getApi() : null;
}
}
Spring Social
Spring Boot
@RestController
@EnableAutoConfiguration
public class AppController {
@RequestMapping("/")
String home() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(AppController.class, args);
}
}
Spring Boot
HTTP
Tail
File
TCP/UDP
JMS
RabbitMQ
Trigger
Filter
Transformer
Splitter
Aggregator
Object-to-JSON
JSON-to-Tuple
HTTP Client
Shell
File
HDFS
JDBC
MongoDB
TCP
Log
Splunk
Source
Processor
(optional)
Sink
Spring XD

source | processor (optional) | sink --parameter=value
stream create --name mongoperf --definition "jms --provider=perftest --destination='epf.audit.queue' | audit-json | mongodb --host='10.94.71.148' --port=11200 --databaseName=upfaudit"
stream create dfs-http --definition "http | file --dir=C:\Users\gtb012\Desktop\ --name=dfs-http-test --suffix=txt" --deploy

Spring XD


Spring XD

- are managed by Spring's IoC container - ApplicationContext
- are declared through XML or Java
- must be non-final and non-static
- usually need default or injection constructors
Beans
can then be injected into instance variables, constructor parameters or setter methods.

More Spring DI
- @Inject vs. @Autowired
- @Named vs. @Qualifier
- @Component
- @Controller
- @Service
- @Repository
- @Scope
- singleton
- prototype
- request
- session
- @Profile
Common Spring Annotations

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<!-- component scan for Spring Config -->
<context:component-scan base-package="com.capitalone.tdp.tdpapp.server.web.spring"
use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.context.annotation.Configuration" />
</context:component-scan>
<!-- PostgreSQL data source bean defined as XML -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost:5432/tdpapp"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
</beans>Application Context

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {
"com.capitalone.tdp.tdpapp.server",
"com.capitalone.epf.logging",
"com.capitalone.epf.configuration.utils",
"com.capitalone.epf.core.jar.springconfig"
})
public class TdpAppSpringConfig {
@Inject
@Named("upf-app-config")
org.apache.commons.configuration.Configuration upfAppConfig;
@Bean
public DataSource dataSource() throws Exception {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl(upfAppConfig.getString("postgres.url"));
dataSource.setUsername(upfAppConfig.getString("postgres.username"));
dataSource.setPassword(upfAppConfig.getString("postgres.password"));
return dataSource;
}
@Bean
@Named("peopleDataSource")
@Scope("request")
public DataSource peopleDataSource() throws Exception {
. . .
}
@Bean(name = {"peopleDao"})
@Inject
public PeopleDao peopleDao(@Named("peopleDataSource") dataSource) {
return new PeopleDao(dataSource);
}
}Java @Configuration

@Repository
public class PeopleDao extends JdbcDaoSupport {
@InjectLogger
private Logger logger;
@Inject
public PeopleDao(final DataSource dataSource) {
setDataSource(dataSource);
}
. . .
}@Service
public class PeopleService {
@InjectLogger
private Logger logger;
@Inject
private PeopleDao peopleDao;
public List<Person> getAllPeople() {
return peopleDao.getAllPeople();
}
}Spring DI


More Spring MVC

public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("application/json");
PrintWriter out = response.getWriter();
out.println("{\"greeting\":\"Hello, World!\"}");
out.close();
}
}<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/helloWorld</url-pattern>
</servlet-mapping>Dispatcher Servlet

web.xml
<?xml version="1.0" encoding="UTF-8" ?>
<web-app id="tdp-app-server" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>tdp-app-server</display-name>
<servlet>
<servlet-name>tdp-app-server</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/tdp-app-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>tdp-app-server</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!-- Configures a default handler serving static resources and the default "/" mapping to the DispatcherServlet. -->
<mvc:default-servlet-handler />
<!-- Activates annotation-based bean configuration. -->
<context:annotation-config />
<!-- Configures the @Controller programming model. -->
<mvc:annotation-driven />
<!-- The servlet's main Spring Controller -->
<context:component-scan base-package="com.capitalone.tdp.tdpapp.server.web.controller" />
</beans>servlet.xml
@Controller
public class HelloController {
@Inject
private Service service;
@RequestMapping(value = "helloWorld", method = RequestMethod.GET)
public @ResponseBody
List<HelloWorld> helloWorld(final String greeting) {
return service.getHellos();
}
@RequestMapping(value="u/{username}/edit", method=RequestMethod.POST)
public String editUser(@PathVariable String username, @RequestBody User newUser) {
service.editUser(username, newUser);
return "edit_user_success";
}
}@Controller

@Configuration
public class AppStringConfig {
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/");
resolver.setSuffix(".jsp");
return resolver;
}
@Bean
public VelocityLayoutViewResolver viewResolverVelocity() {
VelocityLayoutViewResolver resolver = new VelocityLayoutViewResolver();
resolver.setCache(true);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".vm");
resolver.setRequestContextAttribute("requestContext");
resolver.setExposeSpringMacroHelpers(true);
resolver.setToolboxConfigLocation("/WEB-INF/vm/config/velocityTools.xml");
resolver.setLayoutUrl("/WEB-INF/vm/web/layout/layout.vm");
return resolver;
}
}View Resolvers

- Spring Documentation
- GitHub
- spring-projects/spring-mvc-showcase
- spring-projects/spring-xd-samples
- spring-projects/spring-boot/tree/master/spring-boot-samples
- StackOverflow
- questions.kdc.capitalone.com
Spring Resources




deck
By Reid Harrison
deck
- 1,030