看了几天的SpringMVC,换了很多视频,看了很多博客也不是特别懂,直到看到b站上有人分享出了付费版的极客学院的讲解视频我才大致了解了这个框架,结合一篇博客,花了一天写代码,一天debug,总算是成功运行了,学一个框架一开始给你讲大道理讲细节是很难懂的(可能是我太笨),只有跟着几个简单的demo一起做一遍,边做边查相关的资料,debug的时候也能学会很多,几天下来终于明白了学习的方法。
做完demo之后,SpringMVC是将一个web项目的所有东西粘合起来成一个整体的粘合剂,这个比喻再恰当不过了。一个web项目涉及许多的东西,比如jsp文件,各种xml配置,一堆servlet,还有就是配合spring框架使用的各种POJO类,已经我们要写的与数据库相连的DAO层,在SpringMVC的作用就是将这些整合起来,更方便得互相调用。
下面分享一个demo,写了一个简单的登录界面,注册功能,期间用mybatis来操作数据库(当然jdbc也可以,但是会更复杂,mybatis也很好学的),用的ide是idea,maven进行管理,junit进行数据库DAO层测试。
本次项目代码已经上传到github了,有需要的可以下载:https://github.com/iunique/IdeaProject
先看一下大致的骨架,注意一开始初始生成的那个index.jsp要删掉!!这个坑了我好久,因为它的优先级比springMVC设置的更高。
一张图还放不下要放两张。
注意摆放的位置。
然后是maven管理jar包的配置文件pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.springMVC</groupId> <artifactId>springMVC</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>springMVC Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency> <!--springMVCjar包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--mybatis所需jar包配置--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.29</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.3.0</version> </dependency> <!--spring所需jar包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies> <build> <finalName>springMVC</finalName> </build> </project>
首先准备一份数据,进入mysql数据库,我的数据库名称叫mybatis,然后建一张叫user的表
itcreate table user( id int auto_increment primary key, name varchar(20) not null, age tinyint not null, password varchar(20) not null )engine=innoDB; insert into user(name,age,password) values("hjy",18,"123456"); insert into user(name,age,password) values("unique",19,"666666");
我喜欢先从java代码开始写起,那么就先写一个POJO类吧,叫做User.java:
package domain; public class User { private int id; private String name; private int age; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
然后我会写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> <!-- 和Spring整合后environment配置都会被干掉 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理,目前由mybatis来管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池,目前由mybatis来管理 --> <dataSource type="POOLED"><!--有关于mysql数据库的各种信息--> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis" /> <property name="username" value="root" /> <property name="password" value="123456" /> </dataSource> </environment> </environments> <mappers> <!--将操作配置文件User.xml系添加进mapper--> <mapper resource="User.xml" /> </mappers> </configuration>
和打算对数据库进行的操作mybatis的配置文件User.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="test"> <!-- 通过id查询用户 --> <select id="findUserById" parameterType="int" resultType="domain.User"> select * from user where id = #{id} </select> <!--通过name用户--> <select id="findUserByName" parameterType="java.lang.String" resultType="domain.User"> select * from user where name like '${value}' </select> <!--根据name和password查询User--> <select id="checkLogin" parameterType="domain.User" resultType="domain.User"> select * from user where name=#{name} and password=#{password} </select> <!--插入用户信息--> <insert id="insertUser" parameterType="domain.User"> insert into user(name,age,password) values(#{name},#{age},#{password}) <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> select last_insert_id() -- 这里是对于主键属性的id进行赋值 </selectKey> </insert> <!--删除用户信息--> <delete id="deleteUser" parameterType="java.lang.Integer"> delete from user where id=#{id} </delete> <!--更新用户信息--> <update id="updateUser" parameterType="domain.User"> update user set name=#{name},age=#{age},password=#{password} where id=#{id} </update> </mapper>
然后是获得mybatis的session的工具类SessionBean.xml:
package tools; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.*; import java.io.IOException; import java.io.InputStream; public class SessionBean { private final static SqlSessionFactory sqlSessionFactory; static { String resource = "config.xml"; InputStream inputStream=null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } public static SqlSession getSession() { return sqlSessionFactory.openSession(true);//这里设置成true表示支持事务,就是会更新数据库的意思,mybatis默认不支持事务 } }
然后是与数据库相交互的DAO层,UserDao.java:
package dao; import domain.User; import org.apache.ibatis.session.SqlSession; import tools.SessionBean; public class UserDao { private static SqlSession session; static { session= SessionBean.getSession(); } public static User findUserById(int id)//通过id来查找User { return session.selectOne("test.findUserById",1); } public static User findUserByName(String n)//通过name来查找User { return session.selectOne("test.findUserByName",n); } public static User checkLogin(String name,String password) { User user=new User(); user.setName(name); user.setPassword(password); return session.selectOne("test.checkLogin",user); } public static void insertUser(User user)//插入一个User { session.insert("test.insertUser",user); } public static void deleteUser(int i)//删除id为i的User { session.delete("test.deleteUser",i); } public static void updateUser(User user)//根据id更新User信息 { session.update("test.updateUser",user); session.commit();//注意必须要commit } }
写到这里是不是没有用一点SpringMVC的影子呢,没错确实没有,因为他是粘合剂当然是最后加入,继续我们可以写一个测试类来测试目前为止的mybatis的操作有没有错误:
UserDaoTest.java:
package dao; import domain.User; import org.junit.Test; import java.util.List; public class UserDaoTest { @Test//测试单例查找 public void test_findUserById() throws Exception { User user = UserDao.findUserById(1); System.out.println("id:" + user.getId() + " name:" + user.getName() + " age:"+user.getAge()+" password:" + user.getPassword()); } @Test//测试通过用户名查找 public void test_findUserByName()throws Exception { User u=UserDao.findUserByName("hjy"); if(u!=null) { System.out.println("id:" + u.getId() + " name:" + u.getName() + " age:"+u.getAge()+ " password:" + u.getPassword()); } } @Test//测试插入操作 public void test_insertUser()throws Exception { User user=new User(); user.setName("ggboy"); user.setAge(14); user.setPassword("1008611"); UserDao.insertUser(user); User u=UserDao.findUserByName("ggboy"); if(u!=null) { System.out.println("id:" + u.getId() + " name:" + u.getName() + " age:"+u.getAge()+ " password:" + u.getPassword()); } } @Test//测试删除操作 public void test_deleteUser()throws Exception { UserDao.deleteUser(1); test_findUserByName(); } @Test//测试更新操作 public void test_updateUser()throws Exception { User user=new User(); user.setId(1); user.setName("hjy"); user.setAge(10); user.setPassword("99999"); UserDao.updateUser(user); test_findUserByName(); } }
测试结束没有错误就可以开始下一步的操作了,然后就是准备好一系列的页面,我说一下我的分配,首先是登录界面login.jsp,然后是登录失败界面login2.jsp(就是加了一行字而已,从login页面那复制),然后是注册界面regist.jsp,注册失败界面regist2.jsp(也只是加了一行字),success.jsp登录成功界面,会输出欢迎+你的用户名,当然用户名是唯一的。
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>login</title> </head> <body> <form action="login" method="post"> 用户名:<input type="text" name="name"/><br> 密 码:<input type="password" name="password"/><br> <input type="submit" value="登录"><br> <a href="regist">注册</a> </form> </body> </html>
login2.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>login</title> </head> <body> <form action="login" method="post"> 用户名:<input type="text" name="name"/><br> 密 码:<input type="password" name="password"/><br> <input type="submit" value="登录">登录失败,用户名或密码有误<br> <a href="regist">注册</a> </form> </body> </html>
regist.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Regist</title> </head> <body> <form action="registSuccess" method="post"> 用户名:<input type="text" name="name"/><br> 密 码:<input type="password" name="password"/><br> 年 龄:<input type="number" name="age"><br> <input type="submit" value="提交"/> </form> </body> </html>
regist2.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Regist</title> </head> <body> <form action="registSuccess" method="post"> 用户名:<input type="text" name="name"/><br> 密 码:<input type="password" name="password"/><br> 年 龄:<input type="number" name="age"><br> <input type="submit" value="提交"/> 注册失败,用户名已被占用 </form> </body> </html>
success.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Success</title> </head> <body> Success Login!<br> 欢迎${name}; </body> </html>
写到这里,jsp页面中是不是有些你没见过的东西和写法呢,这其中就使用了SpringMVC,首先在web.xml中声明一个解析器(我这么认为)和加入mybatis的配置文件,解析器的作用大概就是对jsp页面的参数进行拦截处理,比如写了一个login,但是一般的写法应该是后面加上一个页面地址才对,那么这个解析器就会根据这个参数到相应的springmvc中的controller类中去找到相应的方法然后对此字符串进行解析后返回
然后重点来了,下面是SpringMVC的核心内容,springmvc-servlet.xml,也就是对这个解析器进行解释的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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!--默认的注解映射的支持 --> <mvc:annotation-driven/> <!--启用自动扫描 --> <context:component-scan base-package="controller"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
这个文件的意思就是将拦截到的字符串前面加上个前缀/WEB-INF/JSP/,后面加上.jsp,现在你明白为什么可以那样写参数了吧,是因为会有解析处理的,还有就是扫描controller包中所有的controller类对其进行正确拦截
下面也是很核心的LoginController.java:
package controller; import dao.UserDao; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.http.HttpServletRequest; @Controller public class LoginController { @RequestMapping(value = "/", method = RequestMethod.GET)//这里表示访问根目录的时候转到login.jsp页面的意思,同样会对该字符串进行路径解析 public String sayHello() { return "login"; } @RequestMapping(value = "login",method = RequestMethod.POST)//这个的意思是拦截到login的字样会加以判断来转移到哪个页面,当然也会加以处理 public String login(Model model, HttpServletRequest request) { String name=request.getParameter("name"); String password=request.getParameter("password"); if(UserDao.checkLogin(name,password)!=null) { model.addAttribute("name",name); return "success"; } else { return "login2"; } } }
然后是RegistController.java:
package controller; import dao.UserDao; import domain.User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.http.HttpServletRequest; @Controller public class RegistController { @RequestMapping(value = "regist",method = RequestMethod.GET) public String regist() { return "regist"; } @RequestMapping(value = "registSuccess",method = RequestMethod.POST) public String registSuccess(HttpServletRequest request,Model model) { String name=request.getParameter("name"); String password=request.getParameter("password"); int age=Integer.parseInt(request.getParameter("age")); if(UserDao.findUserByName(name)!=null) { return "regist2"; } else { User user=new User(); user.setName(name); user.setPassword(password); user.setAge(age); UserDao.insertUser(user); model.addAttribute("name", name); return "login"; } } }
这个类的作用和上面那个差不多,还有一点要说的就是model这个东西,相当于为返回页面添加了一个属性,第一个参数为jsp中你要调用的属性名字,第二个参数为该属性的值,要调用的时候就直接在该页面中用${属性名字}这个样子调用。
还有最后说一下测试的时候,地址栏输入localhost:8080/就可以转到login.jsp页面了,因为这就是SpringMVC解析器的作用,然后再说一个我在写代码过程中的了解的知识:WEB-INF文件tommcat是默认不允许访问的,在web.xml那里设置个welcome标签就可以访问了,当然使用SpringMVC解析也是可以的,这也是其作用之一。
本篇文章希望帮助像我一样被SpringMVC框架困扰的人,写完以后是不是对框架有更了解一些了呢。