目标:提供rest接口给客户端应用调用
基础条件: oracle数据库,jndi方式访问数据库
项目设计如下:
[maven:管理依赖,打包]
//spring-boot的每个starter-xxx本质上就是一个pom,这个pom里面包含相关的依赖
//比如,starter-data-jpa会引入对hibernate的依赖
spring-boot-starter-web:开发controller (暴露rest api)
spring-boot-starter-data-jpa: 采用jpa开发持久层
pom.xml:
<packaging>war</packaging>
<properties>
<spring.boot.version>1.4.2.RELEASE </spring.boot.version>
<ojdbc.version>11.2.0.4</ojdbc.version>
<spring.loaded.version>1.2.6.RELEASE</spring.loaded.version>
<dbcp.version>8.5.4</dbcp.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>${dbcp.version}</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>${ojdbc.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>${spring.loaded.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
项目结构如下:
customer
entity
+ Customer.java
pojo
+ BaseResponse.java
repository
+ CustomerRepository.java
service
api
+ ICustomerService.java
impl
+ CustomerService.java
+ CustomerController.java
+ ApplicationConfig.java
+ Application.java
以下是代码展示和说明:
application.properties
spring.datasource.driverClassName=oracle.jdbc.OracleDriver
spring.datasource.jndi-name=jdbc/customer
entityManagerFactory.packagesToScan=customer.entity
hibernate.dialect= org.hibernate.dialect.Oracle10gDialect
Application.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication(exclude = JmxAutoConfiguration.class)
@EnableTransactionManagement
/**
* 当需要spring-boot生成war包的时候,需要继承SpringBootServletInitializer并重写configure方法;注解@EnableTransactionManagement开启事务管理能力,采用@Transactional注解的方法获得事务管理能力;因为接下来需要手动配置数据库,此处需不包含JmxAutoConfiguration.class, 从而禁用自动配置数据库
*/ public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application){
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(AuthServiceApplication.class, args);
}
}
ApplicationConfig.java
//采用jndi方式访问数据库
/**
* 当需要自定义事务管理器时,需要实现接口TransactionManagementConfigurer,并重写方法annotationDrivenTransactionManager(),让其放回对应的事务管理器,比如此处使用的JpaTransactionManager
*/
@Configuration
@EnableCaching
/**
* CUSTOMER_HOME是自定义的环境变量,此处指部署文件夹的根目录
*/
@PropertySource("file:${CUSTOMER_HOME}/conf/application.properties")
public class ApplicationConfig implements TransactionManagementConfigurer {
@Value("${spring.datasource.jndi-name}")
private String jndiName;
@Value("${entityManagerFactory.packagesToScan}")
private String[] packagesToScan;
@Value("${hibernate.dialect}")
private String hibernateDialect;
private PlatformTransactionManager transactionManager;
@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
@Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
@Override
protected void postProcessContext(Context context) {
ContextResource resource = new ContextResource();
resource.setName(jndiName);
resource.setType(DataSource.class.getName());
context.getNamingResources().addResource(resource);
}
};
}
@Bean
public DataSource jndiDataSource() throws IllegalArgumentException, NamingException {
JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
bean.setJndiName("java:comp/env/" + jndiName);
bean.setProxyInterface(DataSource.class);
bean.setLookupOnStartup(false);
bean.afterPropertiesSet();
return (DataSource) bean.getObject();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder)
throws IllegalArgumentException, NamingException{
Map<String, String> properties = new HashMap<String, String>();
properties.put("hibernate.dialect", hibernateDialect);
return builder
.dataSource(jndiDataSource())
.packages(packagesToScan) //设置表映射的entity目录路径
.properties(properties)
.build();
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
transactionManager = new JpaTransactionManager(entityManagerFactory);
return transactionManager;
}
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return transactionManager;
}
}
Customer.java
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
@Entity
@Table(name = "T_CUSTOMER")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
// 配置entity类注意事项:请确保每一个字段在数据库表中都存在,如果不存在,访问时会报错:invalid column not exists; 比如: @Id private long id;
//要求对应的表中有主键id;如果表(或视图)中没有主键id, 则需要去掉@Id private long id; 并将@Id添加到主键(或唯一键)字段上, 比如:
// @Id @Column(name = “name”) private String name;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="SEQ_CUSTOMER")
@SequenceGenerator(name="SEQ_CUSTOMER",sequenceName="SEQ_CUSTOMER", allocationSize=1)
private long id;
@Column(name = "name")
private String name;
@Column(name = "age")
private int age;
/*此处忽略getter/setter方法*/
}
CustomerRepository.java
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface SaRegisterRepository extends CrudRepository<SaRegister, Long>{
@Query(value = "SELECT T.age FROM T_CUSTOMER T WHERE T.NAME = ?1", nativeQuery = true)
int findAgeByName(String Name);
@Modifying
@Query(value = "UPDATE T_ CUSTOMER T SET T.age = ?1 WHERE T.NAME = ?1", nativeQuery = true)
void updateAgeByName(String Name);
}
ICustomerService.java
public interface ICustomerService {
public BaseResponse findAgeByName(String name);
public BaseResponse updateAgeByName(String name);
}
CustomerService.java
@Service
public class CustomerService implements ICustomerService {
@Autowired
private CustomerRepository customerRepo;
public BaseResponse findAgeByName(String name){
BaseResponse resp = new BaseResponse;
int age = customerRepo.findAgeByName(name);
/*此处忽略对resp的设置*/
return resp;
}
//当执行save即修改/增加操作时, 需要事务支持,因此此处需要@Transactional
@Transactional
public BaseResponse updateAgeByName(Customer customer){
BaseResponse resp = new BaseResponse;
customerRepo.save(customer);
/*此处忽略对resp的设置*/
return resp;
}
}
CustomerController.java
@RestController
@RequestMapping("/api/v1/customer")
public class RegisterController {
@Autowired
public ICustomerService customerService;
@RequestMapping(value = "/add", method = RequestMethod.POST)
public BaseResponse addCustomer(@RequestParam(value = "name", required = true) String name, @RequestParam(value = "age", required = true) int age) {
Customer customer = new Customer();
/*此处忽略对customer的设置*/
registerService.save(customer)
BaseResponse resp = new BaseResponse;
/*此处忽略对resp的设置*/
return resp;
}
}
部署的目录结构如下:
CustomerApp
conf
log
tomcat
bin
conf
webapps
customer
+ customer.war
context.xml //配置数据库
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<Resource auth="Container"
driverClassName="oracle.jdbc.OracleDriver"
maxIdle="30" maxTotal="100"
maxWaitMillis="10000"
name="jdbc/customer"
password="o1230TeSt"
type="javax.sql.DataSource"
url="jdbc:oracle:thin:@localhost:1521:DBCustomer01"
username="app_customer"/>
</Context>
环境变量CUSTOMER_HOME的设置:
setenv.sh
#!/bin/bash
: ${SCRIPTHOME:=`dirname $(readlink -f $0)`}
export CUSTOMER_HOME=${SCRIPTHOME}/../..
setenv.bat
@echo off
set "CUSTOMER_HOME =../.."