项目简介

编写一个简单的JavaWeb登录示例。具有登录功能。成功登录可以显示用户信息;登录失败则有相关提示。

项目的基本框架已经由老师提供,SpringMVC+Mybatis。业务逻辑和视图之间的交互采用Java Server Page(jsp)实现。

数据逻辑和业务逻辑几乎都已经写好,修改jdbc.properties中的配置信息之后,即可执行测试代码/src/test/UserServerTest.java

项目的目录结构如下。

java的项目经验 javaweb项目经验_java的项目经验


本文核心

介绍项目中需要修改的地方。也是我遇到问题的地方。


提前准备

  1. 确保本机安装了Java并配好环境变量
  2. Mysql下载,安装
  3. Navicat或者其他的数据库连接工具下载安装
  4. Tomcat下载安装,然后在Idea中添加Tomcat服务器(这里推荐使用Idea中Plugins Market中的插件Smart Tomcat,比自带的Tomcat插件好用)

作业过程

1.Navicat中建立数据库和表

项目中的/sql/sq.sql是本项目提供的建表脚本。首先在Navicat中连接好自己本机的Mysql,然后新建一个数据库。接着执行这个数据表的脚本即可建表。这一个表足矣。

2.修改jdbc配置文件

如下图,jdbc.url是到本机数据库的链接,common_login是数据库的名称。username和password改为本地mysql的登录信息。

java的项目经验 javaweb项目经验_java的项目经验_02


这个配置文件将在全局上下文配置文件applicationContext.xml中被加载。

java的项目经验 javaweb项目经验_java的项目经验_03


此时可以尝试执行/src/test/UserServerTest.java中的测试代码。

3. 修改UserDao.xml

上一步执行测试代码会报错。

UserDao.xml是Mybatis的核心文件。它将数据库语言sql和MVC中的持久层接口(数据逻辑)映射起来。

由于建表的时候,/sql/sq.sql中建立的字段都是下划线式命名的,比如user_name。然而在UserDao.xml中,sql语句的字段名称是驼峰式的,比如userName。比如插入方法,需要将insert语句后的字段名称改为和数据库一致,都是下划线命名方式

java的项目经验 javaweb项目经验_java的项目经验_04


修改后,测试代码能够成功执行。但是结果有问题。进行查询操作的时候,读不到字段名称为下划线形式的字段值(数据表中只有user_name和real_name是带下划线的)。但是增、删、改在数据库端是显示正常的。这是因为读取的时候,返回的对象的实体类User.java中,其toString()方法是这么写的

java的项目经验 javaweb项目经验_字段_05


又因为在测试代码中,都是直接printlin(user)

System.out.println(user);

调用的就是user中的toString方法,输出字段userName和realName。但是业务逻辑在从数据库返回的对象中

select * from user where uuid = #{uuid}

是找不到字段userName和realName的,因为只有user_name和real_name。因此,对于这种查询方法,还需要在Mybatis的映射配置文件为命名格式不统一的字段再设置一个映射。
UserDao.xml中,添加如下映射:

<resultMap id="userResultMap" type="com.itheima.domain.User">
        <result property="userName" column="user_name"/>
        <result property="realName" column="real_name"/>
</resultMap>

将驼峰式的属性字段映射和数据库中下划线式的列名字段作映射。并将此映射配置引入到对应的查询方法配置中,也是在UserDao.xml中:

<!--查询单个-->
<select id="get" resultType="user" parameterType="int" resultMap="userResultMap">
    select * from user where uuid = #{uuid}
</select>

如上,在<select>标签中添加resultMap属性,其值为<resultMap>标签中的id属性值。

至此,理论上可以成功执行项目中的测试代码,并得到正确的结果。业务逻辑代码几乎不用再改。


4. 修改SpringMVC配置文件 spring-mvc.xml

这里首先在/src/main/webapp/下新建文件夹jsp,这个文件夹下存放.jsp文件。注意,在Idea创建的基于Maven的SpringNMC文件结构下,JSP文件不要放在WEB-INF目录下,不然JSP跳转的时候是找不到的。

java的项目经验 javaweb项目经验_字段_06

spring-mvc.xml文件中已经提供了SpringMVC的扫描注入语句

<!--开启Spring的扫描注入,这里是针对Controller的-->
<context:component-scan base-package="com.itheima.controller"/>

和注解驱动语句

<!--开启SpringMVC的注解驱动,使得URL可以映射到对应的Controller-->
<mvc:annotation-driven/>

需要我们自己添加能够匹配到视图层(View层,也就是jsp文件)的配置语句:

<!--匹配视图-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

之后,SpringMVC中视图和控制器之间进行交互的时候,框架就会去webapp下面找/jsp/文件夹中的.jsp文件。
为了方便项目内url的定位,在pom.xml中引入thymeleaf依赖:

<!--方便url定位的-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
   <version>2.7.0</version>
</dependency>

至此,理论上项目可以通过Tomcat运行起来,在浏览器显示index.jsp


5. JSP文件的编写提要

除了自带的index.jsp,我另外建了三个.jsp文件。

java的项目经验 javaweb项目经验_字段_07

其中user.jsp是必须要有的。因为在给定的控制器层代码UserController.java中,使用了SpringMVC框架的注解

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

@RestController表明此文件是个控制器。@RequestMapping("/user")告诉我们它处理的请求来自于user.jsp。这里的相对路径/user不用改——只要框架能够成功装配和扫描这些注解,就能够成功通过我们在spring-mvc.xml中添加的视图路径配置定位到我们放在/jsp/下的user.jsp。当然,这个user.jsp就是用于登录的页面。
这里将@RestController换为@Controller(好像是因为@RestController不能进行我后面用到的页面跳转方式)。

@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

这个时候,向下阅读UserController.java,你会发现不光是这个类的class外面有注解,其内部的每个公开方法都有注解。比如我们之后要用到的函数login()

@PostMapping("/login")
public Result login(@RequestParam("userName") String userName,@RequestParam("pwd") String password){

这也是SpringMVC注解的方便之处——JSP页面通过链接/user能够访问到UserController.java;通过链接/user/login就能访问到其下的login方法。

index.jsp跳转到user.jsp(登录页面)

index.js直接放主要代码。这里没啥大问题,就是要注意跳转时路径的设置。.jsp之间的跳转是不会去读spring-mvc.xml的。

<body>
        <h2>Hey, dear!</h2>
        <a href="jsp/user.jsp">点我登录</a>
    </body>

user.jsp设置登录表单<form>

一个<form>标签足以完成提交登录信息的任务。user.jsp中代码如下:

<div id="login_frame">

    <p id="image_logo">
    <img src="images/icon_leaf.png" alt="logo"/>
        欢迎登录
    </p>

    <form action="${pageContext.request.contextPath}/user/login" method="post">
        <p>
            <label class="label_input">用户名:</label>
            <label>
                <input type="text" name="userName" class="text_field"/>
            </label>
        </p>

        <p>
            <label class="label_input">密码:</label>
            <label>
                <input type="password" name="password" class="text_field"/>
            </label>
        </p>

        <div id="login_control">
            <input type="submit" value="登录" id="btn_login"/>
        </div>
    </form>
</div>

注意<form>中的action属性,链接到UserController.java中的login方法。method属性为post
最终的提交按钮为<input>标签,type设置为submit

至此,理论上能够完成index.jspuser.jsp的跳转以及点击登录按钮实现页面跳转(现在可能是跳到404)。

完善登录,修改login方法

login方法的类型,是本项目自定义的Result类型。这个键值对对象中可以存储用户对象值和登录的结果信息。可以简单的将其输出到页面上(好像是要使用@RestController标签?)。但是我们要进行页面跳转,就要更改login的类型。

@PostMapping("/login")
    public String login(String userName, String password, Model model){
        Result result;
        User user = userService.login(userName,password);
        if (null != user) {
            // 成功登录
            result = new Result(Code.GET_OK, user);
            DateFormat fd = DateFormat.getDateInstance();
            model.addAttribute("user", user);
            model.addAttribute("result", result);
            model.addAttribute("birthday_date", fd.format(user.getBirthday()));
            return "hello";
        } else {
            // 登录失败,拿到的user对象为null
            result = new Result(Code.GET_ERROR, null);
            model.addAttribute("result", result);
            return "error";
        }
    }

修改后的方法是String类型的。这里返回的串helloerror其实都分别链接到了一个JSP页面——这也是SpringMVC提供的便利。进行业务逻辑处理后,页面跳转。

其中用到了Model类。这个类来源于

java的项目经验 javaweb项目经验_java的项目经验_08


没错,也是框架里的。是一个全局量。在login这边创建一个Model类型的对象model,存入一些键值对。然后在跳转后的JSP页面,这些存入的键能够被页面通过${key.property}或者${key}来调用。比如在hello.jsp中,我就这样来提供用户信息:

<body>
<h2>${user.userName},你好!</h2>
<table border="1">

    <tr>
        <th>真名</th>
        <td>${user.realName}</td>
    </tr>
    <tr>
        <th>性别</th>
        <td>${user.sex}</td>
    </tr>
    <tr>
        <th>生日</th>
        <td>
            ${birthday_date}
        </td>
    </tr>
    <tr>
        <th>卡号</th>
        <td>${user.idCard}</td>
    </tr>

</table>
</body>

其中的user就是在login方法中被存储到mode中的。

model.addAttribute("user", user);
model.addAttribute("result", result);
model.addAttribute("birthday_date", fd.format(user.getBirthday()));

至此,理论上可以完成登录之后跳转页面,显示信息的功能。


6. UI设计、移动端运行

css的设计我直接参考了这位老兄的文章链接。在webapp/jsp文件夹下新建了一个/css/login.css文件。放在/jsp文件夹下也是为了成功引用之,不然可能找不到文件。
然后在JSP文件中通过<link>标签引入之:

<html>
<head>
    <title>Thank you!</title>
    <link rel="stylesheet" type="text/css" href="./css/login.css"/>
</head>

作业要求是能够按照手机端的分辨率运行。
首先要能够在手机端跑起来:目前在校,可以通过WIFI确保手机和台式机在同一个局域网(校外VPN应该也行吧)。在电脑端把程序用Tomcat跑起来,然后打开手机浏览器,输入台式机IP地址加Tomcat端口号8080和项目名称,比如

https://177.178.179.180:8080/program_name

其实也就是将电脑端的显示链接中,本地IP地址127.0.0.1换成局域网IP地址就行了。

然后,为了让页面在手机端看起来不鬼畜,我参考了这个链接,在JSP页面中都添加了

<head>
    <meta name="viewport" content="width=device-width; initial-scale=1.4; minimum-scale=1.0; maximum-scale=2.0"/>
</head>

然后调整了CSS文件的配置,更换竖版的背景图等等。

7. 细节

在出错页面error.jsp用了一个简单的javascript,实现了定时跳转回到登录页面user.jsp

<html>
<script type="text/javascript">
    let t = 3;
    setInterval('jump()', 1000);
    function jump () {
        if(t===0) {
            window.location.href = "../jsp/user.jsp";
        }
        t--;
    }
</script>

最终效果


源码

百度网盘链接 提取码:digb


后记

说实话我已经立志要做硬件了。硬件和软件从来不是割裂的,学习计算机软件要考虑硬件,学习计算机硬件要应用到软件。或者说,是自己计算机知识体系的一个深入和扩充吧。研究生也是在学习吗嘛。
也是接着软件实践开发这个课程,有个机会重温一下软件的项目。不得不说Spring系列的框架提供的注解功能,写业务逻辑简直不要太舒服。Mybatis一起用,屏蔽掉数据逻辑简直不要太轻松。只不过用的好用的熟练,那还是要功夫的。