Spring学习笔记(三)——配置篇


前提

这篇博文是这套Spring学习笔记的第三篇——配置篇,主要内容包含Spring框架的获取以及如何创建一个可以作为基础模板的使用Spring框架的Java Web工程。如果需要了解有关Spring的综述信息或博文的索引信息,请移步:
《综述篇》


获取Spring框架源码

就像游戏中的好装备,开发者不会让玩家轻易获得一样,凡是被人们广为传唱的好软件、优秀源代码,几乎没有一个的网站上有“Download”这个按钮。我猜这可能算是一种筛选吧,即“能被小小的困难轻易打败的人不配拥有宝剑”之类…

言归正传,首先看一下Spring的官方网站
Spring官方网站

并没有Download按钮。PROJECT?不存在的。只不过依次点击PROJECT->SPRING FRAMEWORK会跳转到Spring框架的综述页面,里面有一部分有用的信息如下:
Minimum requirements
这是一份Spring Framework个版本对JDK的最低要求说明。因为我的PC和服务器装的都是JDK 8.0,所以选择4.0以上版本的Spring Framework就可以。

最终,Spring Framework官方仓库地址还是被我找到了(鬼知道是怎么找到的)。打开之后是一份比较长的列表,包含了Spring Framework所有的版本。可以根据上述对应关系和自己机器上JDK的版本选择合适的Spring Framework版本。

以4.x的最后一个版本4.3.9为例,点击4.3.9.RELEASE进入该目录,然后点击第一个文件“~dist.zip”,下载Spring Framework 4.3.9的源码。
4.3.9RELEASE
下载完成后打开压缩包,把libs文件夹解压出来,然后打开解压生成的libs文件夹
lib文件夹
可以看到,一共61个文件,且三个三个成组出现的,每组都包含X.jar,X-javadoc.jar和X-source.jar。我们挑出所有的X.jar,一共21个,把他们复制出来放进一个文件夹中,这些就是Spring Framework 4.3.9的所有源码的Jar包。


创建Java Web工程

为了保持一致性,我们继续使用NetBeans作为开发用的IDE,关于其下载和安装与创建一个Java Web工程的过程请完全按照我的《Java Web的编写》这篇博文,看到“开始撸码!”这个章节之前就可以了。示例工程的名称仍为MyFirstWebApp

数据库也沿用《MySQL数据库的建立》这篇博文中的教程,创建一个名为myfirstapp的数据库,其中只有一张user表,包含Id、用户名和密码三个字段。

其中略有不同的是:
①我将所提供的云盘资源中MySql Connector的版本提升到了5.1.46,因为继续用3.1.14版本会报错;
②需要以相同的方式将上述Spring Framework那21个Jar包也一并添加到库中去;
③需要额外添加dbcp2、pool2和aspectjweaver的Jar包到库中。
dbcp2链接 密码:qzu4
pool2链接 密码:9pe7
aspectjweaver链接 密码:6q0z


创建Spring配置文件

依次右键点击源包->新建->Spring XML配置文件
Spring XML配置文件
命名为 applicationContext 后点击下一步
applicationContext
勾选aop、context、p和tx这四个选项 后点击完成
名称空间
新生成的applicationContext.xml文件的内容如下:

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
">

</beans>

注意:接下来所添加的代码全部都是在<beans>标签中(就是上述代码倒数第二行的空行处)做的。

添加组件扫描

    <context:component-scan base-package="com.implementist.MyFirstWebApp.dao"/>
    <context:component-scan base-package="com.implementist.MyFirstWebApp.service"/>

这两行的作用是让IoC容器扫描这两个包,自动注入所需的依赖。 当然目前工程中的源包只创建到了MyFirstWebApp这一层,上述的dao和service包尚未创建。

配置数据源和jdbc模板

    <!-- 配置数据源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
          destroy-method="close" 
          p:driverClassName="com.mysql.jdbc.Driver"
          p:url="jdbc:mysql://localhost:3306/myfirstapp?characterEncoding=utf8" 
          p:username="root"
          p:password="" />

    <!-- 配置Jdbc模板  -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
          p:dataSource-ref="dataSource" />

这里有两个bean:
第一个dataSource是数据源。有没有感觉很眼熟?其实它和不管Java文件中配置数据源还是XML文件里配置数据源都挺像的,都是些字符串,Url、端口、数据库、数据库账号、密码这些,没啥看不懂的,就不细说了。

第二个是jdbc模板,它引用了上面定义的dataSource作为数据源。 说到这个词可能大家没有印象,你回到《综述篇》去看一下就知道了,Spring就是把与数据库相关的定义连接、处理异常、关闭连接等各种重复累赘的代码封装到了Jdbc这个类中,以此来减少开发者实现数据库操作所需的代码量。

配置事务管理器

    <!-- 配置事务管理器 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
          p:dataSource-ref="dataSource" />

关于事务的定义我目前还没有完全理解,但这段代码是必须的,后面的代码会引用transactionManager这个Bean。

配置AOP

    <!-- 通过AOP配置提供事务增强,让service包下所有Bean的所有方法拥有事务 -->
    <aop:config proxy-target-class="true">
        <aop:pointcut id="serviceMethod"
                      expression=" execution(* com.implementist.MyFirstWebApp.service..*(..))" />
        <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>

因为对于AOP本身就还没有理解透,因此这部分代码暂时也不知道怎么解释,后面的博文一定会解释清楚的。


启动Spring容器

注意:以下操作在web.xml中的<web-app>标签中进行

    <!-- 从类路径(即默认包)下加载我们之前创建的Spring配置文件 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
   
    <!-- 启动Spring容器的监听器 -->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

这段代码使Java Web程序在启动时自动加载applicationContext.xml中的配置信息并启动Spring容器。


配置请求调度器

此时需要在源包下面以与applicationContext.xml同样的方式创建一个spring-mvc.xml,其内容如下:

<?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-4.3.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
    <context:component-scan base-package="com.implementist.MyFirstWebApp.controller"/>
</beans>

注意:以下操作在web.xml中的<web-app>标签中进行

现在以一个servlet作为请求分派器:

    <servlet>
        <!-- 此处定义分派器的名称为dispatcher -->
        <servlet-name>dispatcher</servlet-name>
        <!-- 这个DispatcherServlet是Spring框架中的类 -->
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 从类路径(即默认包)下加载我们创建的Spring配置文件 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Servlet映射 -->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <!-- 这里指定接受任意请求 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

下面进入到Java代码的编写中,我们以一个简单的用户登录功能为例

四个包与四个类

首先说一下创建包的方式,后面四个包的创建方式相同,名字不同:
①首先看到工程结构,经过我们之前的配置,变成了如下的样子:
工程结构

②此时依次右键点击源包->新建->Java包
创建包
把包名换成我们需要的包名之后点击完成按钮就可以了。

domain包与User类

我们先创建一个com.implementist.MyFirstWebApp.domain包,然后在包里面创建一个User类

    private int id;
    private String username;
    private String password;
    ......

一共这三个字段,getter和setter省略。

dao包和UserDAO

创建一个和上面前缀相同的dao包,再在包里面创建一个UserDAO类

@Repository  //注①
public class UserDAO {

    @Autowired  //注②
    private JdbcTemplate jdbcTemplate;

    User user = null;

    public User queryUserByUserName(String username) {
        String sqlStatement = "SELECT * FROM user WHERE UserName=?";
        jdbcTemplate.query(sqlStatement, new Object[]{username}, (rs) -> {
            if (rs.isFirst()) {
                user = new User();
                user.setId(rs.getInt("Id"));
                user.setUsername(username);
                user.setPassword(rs.getString("Password"));
            }
        });
        return user;
    }
}

这个DAO中目前只写了按用户名查找用户信息的函数。

注释:
①在添加组件扫描那一小节中,有dao这个包名,当我们给这个类冠以@Repository这个注解时,Spring容器在扫描dao包中的类时,会把UserDAO识别为一个bean,亦即这个类的实例化工作之后就交给Spring IoC容器来管理了;
②还记得我们在applicationContext.xml中配置的数据源和jdbcTemplate吗,当我们在程序中的任何位置定义一个jdbcTemplate变量并给他冠以@Autowired注解时,IoC容器会自动使用配置文件中的信息来实例化这个变量。

service包和UserService

创建一个和上面前缀相同的service包,再在包里面创建一个UserService类

@Service  //注①
public class UserService {

    @Autowired  //注②
    private UserDAO userDAO;

    //判断用户名和密码是否正确
    public boolean verifyLogin(String username, String password) {
        User user = userDAO.queryUserByUserName(username);
        return null != user && password.equals(user.getPassword());
    }
}

注释:
①和dao相同,service包也会被扫描,被冠以@Service注解,指定它是一个服务层的类,和UserDAO类似;
②和jdbcTemplate类似,但是不同之处在于这个userDAO不是从配置文件里找的,因为UserDAO类被冠以了@Repository注解,所以IoC容器会创建一个其实例给userDAO这个变量引用。

controller包和UserController

创建一个和上面前缀相同的controller包,再在包里面创建一个UserController类

@Controller  //注①
public class UserController {

    @Autowired  //注②
    private UserService userService;

    @RequestMapping("Login")  //注③
    private void handleLoginRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
        try (PrintWriter out = response.getWriter()) {
            request.setCharacterEncoding("utf-8");

            //获得请求中传来的用户名和密码
            String username = request.getParameter("UserName").trim();
            String password = request.getParameter("Password").trim();

            //密码验证结果
            boolean result = userService.verifyLogin(username, password);
            out.write(String.valueOf(result));
        }
    }
}

注释:
①controller这个包同样也会被Spring容器扫描到,不同的是我们把它的组件扫描定义在了spring-mvc.xml文件中了。被冠以@Controller的类被指定为控制层的类。
②自动装配userService,老生常谈了。
③请求映射,只有叫做“Login的请求才会被handleLoginRequest函数处理”


最后一步

一般情况下,所有该写的代码都写完了,但是我想额外加上一步。按照上述配置,我们登录时需要使用形如以下的链接:

http://1.1.1.1/Login

同理,注册的时候就需要:

http://1.1.1.1/Register

这样URL实在是太“丑”了,我们希望URL后面不跟请求类型,服务器自动根据请求参数中的RequestType判断是哪种请求,那么我们需要在controller包里额外加一个RequestController

@Controller
public class RequestController {

    @RequestMapping("")
    public ModelAndView dispatch(HttpServletRequest request, HttpServletResponse response) {
        String RequestType = request.getParameter("RequestType");
        return new ModelAndView("forward:" + RequestType);
    }
}

说明
这段代码的意思是:提取任意请求中的RequestType参数,然后根据请求类型把请求转发出去。此时,如果RequestType=Login,请求就会分配给handleLoginRequest这个函数去处理。


工程的整体结构

所有的代码都写完了,我们看一下这个工程的结构
工程的整体结构
分门别类,是不是看着很清爽!


测试一下

现在,部署一下WAR包,我们启动XAMPP控制面板上的Tomcat和MySQL,打开浏览器,在URL中输入:

http://服务器IP/?ReuqestType=Login&UserName=Jackson&Password=1234567890

容许我偷个懒,就不往服务器上放了,在PC上测试一下。
测试结果

解释:
①为了测试方便,我用GET方式发送的请求,如果在客户端写明用POST方式请求,参数就不会出现在URL中,试想一下,URL中"?"以及后面的字符都没有了,是不是很干净?!
②这里的URL并未出现MyFirstWebApp这个工程名,是因为,我在Tomcat完成了对其的部署之后,将XAMPP/tomcat/webapps/MyFirstWebApp这个文件夹的名字改成了"ROOT",ROOT是Tomcat服务器的默认Web APP路径,访问时不需要加工程名称。


后记

1.这篇博文确实比较长,从时间上来说,断断续续得写我一共花了三天时间。所谓万事开头难,配置的过程确实繁琐,但是这整个小模板建立起来之后,在当前项目上,以后随着学习的深入,就可以不断地扩展;在以后的项目中也可以直接复制过去,改改包名就可以复用了。

2.关于代码的问题,我原本想打包一下这个工程分享给大家的。但是后来想了一下,其实这只是第一步,代码也不难,要学习一个东西还是需要去犯错的。因此就不给什么模板代码了,我会尽量保证博文中的代码、逻辑、顺序没有缺失和错误。

3.如果在实现中出现了难以解决的问题,请直接在博文下方评论或者发邮件到我的邮箱:implementist@outlook.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IMplementist

你的鼓励,是我继续写文章的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值