通过一个单词本程序,记录javaWeb的基本流程

环境准备

TOOLS VERSION
Maven 3.8.4
MyBatis 3.5.9
MySQL 8.0.28
Tomcat 10.0.8
Servlet 4.0.1
JSP 2.3.3
JSTL 1.2
Taglibs 1.2.5

使用Maven创建javaWeb项目结构

  • 首先配置一下Maven的本地仓库
    ..\apache-maven-3.8.4\conf\settings.xml中修改或添加标签<localRepository>..\apache-maven-3.8.4\repo</localRepository>,否则其默认的仓库位于c盘的..\用户\..\.m2\repository中。
  • 配置阿里云的镜像仓库以便下载依赖
<mirrors>
    <mirror>
      <id>aliyunmaven</id>
      <mirrorOf>*</mirrorOf>
      <name>阿里云公共仓库</name>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
</mirrors>
  • maven web项目结构

下载依赖

在pom.xml文件中引入坐标以下载依赖

要使用JSTL需要导入JSTL与Taglibs两个坐标,并且要在JSP页面中通过标签引入<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>。Servlet与JSP的作用域scope为provided,是因为其在Tomcat中已经实现了,所以打包成war包后是不需要的。

此处有一个问题,在idea中使用maven时需要在idea里配置的,要选择引入哪里的maven配置文件,不然会使用默认的C盘里的配置文件,从而无法将jar包存入本地仓库。

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.9</version>
</dependency>

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.3</version>
    <scope>provided</scope>
</dependency>

<!--这是正确的包-->
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/taglibs/standard -->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>


<!-- 下面这两个是错误的包 -->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
<dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.taglibs/taglibs-standard-impl -->
<dependency>
    <groupId>org.apache.taglibs</groupId>
    <artifactId>taglibs-standard-impl</artifactId>
    <version>1.2.5</version>
    <scope>runtime</scope>
</dependency>
  • 此外,还有一个Tomcat插件用以方便开发阶段的测试
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.tomcat.maven</groupId>
      <artifactId>tomcat7-maven-plugin</artifactId>
      <version>2.2</version>
    </plugin>
  </plugins
</build>

在idea中配置数据库

选择右边栏的Dadabase标签,点击加号选择MySQL,弹出界面,填写用户名和密码,以及要连接的数据库名称。点击Test Connection可以查看是否连接成功。

容易出现一个问题,及idea与MySQL的时区不同步,显示Go to ‘Advanced’ tab and set ‘serverTimezone‘ property manually的错误提示。则需要修改idea的时区,及点击Advanced标签,找到serverTimezone选项,填入"CST"。

配置MyBatis

首先要编写MyBatis的核心配置文件,即mybatis-config.xml文件。其配置的基本内容如以下代码所示。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/english_words?useSSL=false"/>
        <property name="username" value="root"/>
        <property name="password" value="*****"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

其中,driver是jdbc驱动包名,url的格式为:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数名1=参数值1...,另外,如果连接本地mysql且端口号为默认的3306,则可以简写成jdbc:mysql:///数据库名称?参数名1=参数值1...,用户名与密码为mysql的用户名与密码。这之中的参数useSSL是一种加密的安全连接机制,设定为false可以避免警告提示。environments里可以配置多个environment,用来切换不同阶段的数据库源,如开发环境与测试环境所用的数据库源不一样。transactioinManager是用来处理事物的,之后会由Spring来代替。

另外,还要编写SQL的映射文件,用以统一管理SQL语句。

  1. 首先要在resources目录下创建一个mapper目录,并在目录里创建映射文件,此处为WordsMapper.xml
    在映射文件中写如基本的配置信息,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.WordsMapper">
  <select id="selectAll" resultType="pojo.Words">
    select * from words;
  </select>
</mapper>

其中namespace是名称空间,id是该sql语句的唯一标识符,而resultType是返回结果的类型。

使用Mapper代理开发,用来解决硬编码问题,同时给予IDE代码自动补全的能力,提高效率

  1. 首先要定义与SQL映射文件同名的Mapper接口文件,并且将接口与映射文件放在同一目录下

  2. 设置SQL映射文件中的namespace属性为Mapper接口全限定名,如上的namespace="mapper.WordsMapper"

  3. 在Mapper接口文件中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致。接口中方法定义如下:

public interface WordsMapper {
    List<Words> selectAll();
}
  1. 于是就可以在写代码时通过SqlSession的getMapper方法获取Mapper接口的代理对象,然后调用对应方法完成sql语句的执行。如下:
WordsMapper wordsMapper = sqlSession.getMapper(WordsMapper.class);
List<Words> words = WordsMapper.selectAll();

需要注意的是mybatis-config.xml文件中的mappers标签中需要注册<mapper resource="mapper/WordsMapper.xml"/>

  1. 最后在mybatis-config.xml中进行typeAliases别名设置,别名设置可以扫描所有pojo目录下的实体类,并且不区分大小写,即pojo.User可以写成user,当包名很长时,这样做是方便的。
<typeAliases>
  <package name="pojo" />
</typeAliases>

//WordsMapper.xml文件中可以更改为
resultType="words"

以上,环境准备完成。

  • 此时的mybatis-config.xml文件内容为
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <typeAliases>
    <package name="pojo" />
  </typeAliases>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/english_words?useSSL=false"/>
        <property name="username" value="root"/>
        <property name="password" value="*****"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="mapper/WordsMapper.xml"/>
  </mappers>
</configuration>
  • 此时,WordsMapper.xml内容为
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.WordsMapper">
  <select id="selectAll" resultType="words">
    select * from words;
  </select>
</mapper>

创建MVC项目结构

  • mapper目录中存放sql映射的接口文件
  • pojo目录中存放实体类,并包含getter&setter,和toString方法
  • service目录是MVC中的逻辑处理层,负责组合数据
  • util目录是存放工具包
  • web目录是controller层,负责控制
  • resources目录中存放配置文件以及一些图片等,当maven打包后会和java放在一起,同目录名会被放在同一目录下。
  • webapp存放web配置文件以及html和jsp等。

MVC实现

  1. 实现DAO层,需要编写sql映射文件WordsMapper.xml和定义接口文件WordsMapper的selectAll方法。上述已实现。

  2. 编写sqlSessionFactory工具类,用以避免重复的代码,且SqlSessionFactory工厂只需要创建一次,不要重复创建,所以可以通过静态代码块来解决,因为静态代码块随着类的加载只会执行一次。

首先要明确调用Sql映射的步骤:

  • 读取mybtis-config.xml配置文件

  • 通过配置信息构建工厂类

  • 通过openSession()方法获取sqlSession对象

  • 通过sqlSession.getMapper(WordsMapper.class)获取WordsMapper接口类型对象

  • 通过调用wordsMapper.selectAll()方法执行SQL

  • 最后要记得关闭连接,sqlSession.close()

  • 以下代码的工厂类只执行了一次,每一次返回的都是同一个对象。

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class SqlSessionFactoryUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        String resource = "mybatis-config.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }
}
  1. 实现Service层,其步骤已在上一点说明
public class WordsService {

    public List<Words> selectAll() {
        //调用WordsMapper.selectAll()方法
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        WordsMapper wordsMapper = sqlSession.getMapper(WordsMapper.class);
        List<Words> words = wordsMapper.selectAll();
        sqlSession.close();
        return words;
    }
}
  1. 实现controller(Web)层,编写servlet的代码
  • 首先要调用Service层完成查询,service对象的创建需要多次用到,所以应放在方法外
  • 然后将查询结果存入request域中
  • 最后转发到一个JSP中处理,需要理解的是,JSP其实是一个Servlet文件,通过Tomcat将JSP转译成Sevlet文件,其实际代码是由write方法一行行将html代码写入,其中包含了从数据库中取出的数据,称之为动态。
@WebServlet("/selectAllServlet")
public class SelectAllServlet extends HttpServlet {

    private WordsService wordsService = new WordsService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Words> words = wordsService.selectAll();
        req.setAttribute("words", words);
        req.getRequestDispatcher("/words.jsp").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
  • HttpServlet是Servlet的实现类,封装了对http协议的解析方法
  1. 编写words.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>记单词</title>
</head>
<body>
    <table>
        <tr>
            <th>序号</th>
            <th>英文</th>
            <th>中文</th>
        </tr>
        <c:forEach items="${words}" var="word">
            <tr>
                <td>${word.id}</td>
                <td>${word.english}</td>
                <td>${word.chinese}</td>
            </tr>
        </c:forEach>

    </table>
    <h1>${words}</h1>
</body>
</html>
  • 此处在运行时遇到一个问题,就是导错了jstl和taglibs的jar包,然后就会报错:
    java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/LoopTag,这个错误就是由于jstl包导错的原因,jstl在maven上有好几个分不清,应该是如下
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/taglibs/standard -->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
  1. 写一个index.html文件,内容为<a href="/EnglishWords/selectAllServlet">查询所有</a>

运行

测试时可以利用maven的插件tomcat7:

或者mvn package打包,将其war包放入Tomcat目录中的webapps目录下,启动Tomcat即可在localhost:8080/EnglishWords下访问。

  • 这里遇到了一个很坑的问题,Tomcat10版本和Servlet版本是不兼容的,如果将war包放在版本是10的Tomcat中就会出现如下的404和服务器500的问题,解决的办法就是把Tomcat10换成Tomcat8

或者

总结

效果:

遇到了很多问题,记录下来,整个javaWeb的流程基本了解。

posted @ 2022-03-25 20:06  ··十方··  阅读(58)  评论(0)    收藏  举报