项目学生:Web服务集成

这是Project Student的一部分。 其他职位包括带有Jersey的 Web服务 客户端,带有Jersey的 Web服务服务器业务层具有Spring数据的持久性和分片集成测试数据

早些时候,我们成功地针对持久性/业务层(使用嵌入式H2数据库)和REST服务器/客户端层(使用Jetty服务器)运行了集成测试。 现在是时候将所有内容编织在一起了。

幸运的是,我们已经准备好所有代码并进行了测试。 现在我们要做的就是创建一些配置文件魔术。

局限性

  • 用户身份验证 –尚未进行身份验证的工作。
  • 加密 –尚未对通信进行加密。

容器管理的数据源和JNDI

容器管理的数据源对许多开发人员而言声誉不佳,我不确定为什么。 可能与容器管理的持久性(CMP)混淆?

无论如何,容器管理的数据源背后的想法很简单。 您无需弄清楚如何在已部署的系统中维护数据库连接参数-无需修改已部署的Web应用程序(不安全)或从文件系统读取文件(您可能无法访问)等您只需将问题交给维护Web服务器/应用服务器的人员,然后通过JNDI检索值。

Tomcat和Jetty需要在XML文件中进行手动配置。 像JBoss和GlassFish这样的更高级的应用服务器,使您可以通过漂亮的GUI配置数据源。 其实并不重要,因为您只需要执行一次。 Tomcat 7Jetty的说明

Tomcat的关键点是服务器库位于$ CATALINA_HOME / lib下 ,并且可能不在您期望的位置。 例如,在Ubuntu中,它是/ usr / share / tomcat7 / lib ,而不是/ var / lib / tomcat7 / lib 。 其次,如果未从.war文件中提取META-INF / context.xml文件,则必须将其放置在conf / Catalina / localhost / student-ws-webapp.xml (或任何已命名为.war文件的文件)下)。 后者会覆盖前者,因此通常将.war文件设置为在开发环境中运行,然后在测试和生产环境中覆盖配置。

META-INF / context.xml (Tomcat)

<?xml version="1.0" encoding="UTF-8"?>
<Context>

    <Resource name="jdbc/studentDS"
        auth="Container"
        type="javax.sql.DataSource"
        driverClassName="org.postgresql.Driver"
        url="jdbc:postgresql:student"
        username="student"
        password="student"
        maxActive="20"
        maxIdle="10"
        maxWait="-1"
        factory="org.apache.commons.dbcp.BasicDataSourceFactory" />

</Context>

值得注意的是,通过JNDI(作为java.lang.String)传递加密密钥很简单。 对于修改已部署的Web应用程序或访问服务器的文件系统的需求,这具有与前面讨论的相同的好处。

(由于您希望实际的加密密钥既需要JNDI密钥又需要基于文件系统的盐,因此实现起来要复杂一些,但这在webapp的初始部署过程中很容易处理。)

JPA配置

我们的persistence.xml文件非常少。 我们通常需要两个持久性单元,一个用于JTA事务(生产),另一个用于非JTA事务(开发和测试)。

META-INF / persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
   http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
	version="1.0">

	<persistence-unit name="studentPU-local"
		transaction-type="RESOURCE_LOCAL">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
		<non-jta-data-source>jdbc/studentDS</non-jta-data-source>
	</persistence-unit>
</persistence>

网页配置

web.xml文件与集成测试中使用的文件几乎相同。 关键区别在于,它为容器提供的数据源获取资源引用。

WEB-INF / web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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>Project Student Webservice</display-name>

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            com.invariantproperties.sandbox.student.config.PersistenceJpaConfig
            com.invariantproperties.sandbox.student.config.BusinessApplicationContext
            com.invariantproperties.sandbox.student.webservice.config.RestApplicationContext
        </param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>REST dispatcher</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
        <init-param>
            <param-name>spring.profiles.active</param-name>
            <param-value>test</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>REST dispatcher</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    <resource-ref>
        <description>Student Datasource</description>
        <res-ref-name>jdbc/studentDS</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
</web-app>

弹簧配置

由于两个更改,持久层的Spring配置与以前有很大不同。 从风格上讲,由于不再需要处理嵌入式数据库,因此可以使用标准配置文件而不是配置类。

更为重要的更改是,我们已将所有数据源配置移至容器,并且可以从我们的spring配置中删除它。 我们需要指向正确的数据源和持久性单元,仅此而已!

applicationContext-dao.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.2.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.2.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-3.2.xsd

http://www.springframework.org/schema/data/jpa

http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd

http://www.springframework.org/schema/jee

       http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">

    <context:property-placeholder location="WEB-INF/database.properties" />

    <context:annotation-config />

    <!-- we use container-based datasource -->
    <jee:jndi-lookup id="dataSource" jndi-name="${persistence.unit.dataSource}"
        expected-type="javax.sql.DataSource" />

    <bean name="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="persistenceUnitName" value="${persistence.unit.name}" />
        <property name="packagesToScan" value="${entitymanager.packages.to.scan}" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>
    </bean>

    <bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />

    <bean name="exceptionTranslation"
        class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

    <tx:annotation-driven transaction-manager="transactionManager"
        proxy-target-class="false" />

</beans>

我们的属性文件仅包含数据源的名称,持久性单元名称以及包含JPA批注的要扫描的软件包列表。

WEB-INF / database.properties

# jpa configuration
entitymanager.packages.to.scan=com.invariantproperties.sandbox.student.domain
persistence.unit.dataSource=java:comp/env/jdbc/studentDS
persistence.unit.name=studentPU-local

数据库架构和安全性

最后,集成测试可以使用Hibernate自动创建功能,但是我们应该始终在开发和生产环境中明确维护我们的架构。 除了避免自动化工具以意想不到的方式发挥作用而带来的潜在问题之外,这还使我们能够维护基础架构的价值。

在投入生产之前,编写和测试升级和降级脚本非常重要。 如果出现问题,我们总是需要一种可以正常恢复的方法。

更重要的是,我们的数据库架构应始终由Webapp之外的其他用户拥有。 例如,Web应用程序可以对“学生所有者”创建的表使用“学生用户”。 这将防止使用SQL注入的攻击者删除或修改表。

--
-- for security this must run as student-owner, not student-user!
--

--
-- create an idempotent stored procedure that creates the initial database schema.
--
create or replace function create_schema_0_0_2() returns void as $$
declare
    schema_version_rec record;
    schema_count int;
begin
    create table if not exists schema_version (
        schema_version varchar(20) not null
    );

    select count(*) into schema_count from schema_version;

    case schema_count
        when 0 then
            -- we just created table
            insert into schema_version(schema_version) values('0.0.2');
        when 1 then
            -- this is 'create' so we only need to make sure it's current version
            -- normally we accept either current version or immediately prior version.
            select * into strict schema_version_rec from schema_version;
            if schema_version_rec.schema_version  '0.0.2' then
                raise notice 'Unwilling to run updates - check prior version';
                exit;
            end if;      
        else
            raise notice 'Bad database - more than one schema versions defined!';
            exit;
    end case;

    -- create tables!

    create table if not exists test_run (
        test_run_pkey int primary key,
        uuid varchar(40) unique not null,
        creation_date timestamp not null,
        name varchar(80) not null,
        test_date timestamp not null,
        username varchar(40) not null
    );

    create table if not exists classroom (
        classroom_pkey int primary key,
        uuid varchar(40) unique not null,
        creation_date timestamp not null,
        test_run_pkey int references test_run(test_run_pkey),
        name varchar(80) not null
    );

    create table if not exists course (
        course_pkey int primary key,
        uuid varchar(40) unique not null,
        creation_date timestamp not null,
        test_run_pkey int references test_run(test_run_pkey),
        name varchar(80) not null
    );

    create table if not exists instructor (
        instructor_pkey int primary key,
        uuid varchar(40) unique not null,
        creation_date timestamp not null,
        test_run_pkey int references test_run(test_run_pkey),
        name varchar(80) not null,
        email varchar(200) unique not null
    );

    create table if not exists section (
        section_pkey int primary key,
        uuid varchar(40) unique not null,
        creation_date timestamp not null,
        test_run_pkey int references test_run(test_run_pkey),
        name varchar(80) not null
    );

    create table if not exists student (
        student_pkey int primary key,
        uuid varchar(40) unique not null,
        creation_date timestamp not null,
        test_run_pkey int references test_run(test_run_pkey),
        name varchar(80) not null,
        email varchar(200) unique not null
    );

    create table if not exists term (
        term_pkey int primary key,
        uuid varchar(40) unique not null,
        creation_date timestamp not null,
        test_run_pkey int references test_run(test_run_pkey),
        name varchar(80) not null
    );

    -- correction: need to define this!
    create sequence hibernate_sequence;

    -- make sure nobody can truncate our tables
    revoke truncate on classroom, course, instructor, section, student, term, test_run from public;

    -- grant CRUD privileges to student-user.
    grant select, insert, update, delete on classroom, course, instructor, section, student, term, test_run to student;

    grant usage on hibernate_sequence to student;

    return;
end;
$$ language plpgsql;

-- create database schema
select create_schema_0_0_2() is null;

-- clean up
drop function create_schema_0_0_2();

整合测试

我们可以重用来自Web服务服务的集成测试,但是自1以来,我还没有将其复制到该项目中。我讨厌复制代码,最好将集成测试放入服务器和webapp都使用的单独项目中,以及2)配置Jetty来提供JNDI值很容易,但是由于某种原因,记录在案的类抛出了异常,并且花很多时间进行研究还不够重要(此时)。

源代码

更正

提供的模式忽略了创建新对象所需的“ hibernate_sequence”。 它必须由“学生”用户定义并可读。


翻译自: https://www.javacodegeeks.com/2014/01/project-student-webservice-integration.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值