SpringMVC学习笔记(一)--SpringMVC框架+Mybatis+maven+C3p0实现用户登录
前言:最近在做一个小项目,要实现登录功能,因为SSM框架比较火所以就学了一下,首先学的是maven,主要是用来管理jar包方便,然后是Myabtis如何去操作数据库,再是SpringMVC框架中的controller如何接受前端发来的请求以及操作数据库。
一:先看一下我的maven项目的框架
二:配置文件
1:web.xml文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name>zongjin</display-name> 8 <welcome-file-list> 9 <welcome-file>index.html</welcome-file> 10 <welcome-file>index.htm</welcome-file> 11 <welcome-file>index.jsp</welcome-file> 12 <welcome-file>default.html</welcome-file> 13 <welcome-file>default.htm</welcome-file> 14 <welcome-file>default.jsp</welcome-file> 15 </welcome-file-list> 16 17 18 <!--配置servlet,它的类不用写,直接调用 --> 19 <servlet> 20 <servlet-name>spring</servlet-name> 21 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 22 <init-param> 23 <param-name>contextConfigLocation</param-name> 24 <param-value>classpath*:config/sping.xml</param-value> 25 </init-param> 26 <load-on-startup>1</load-on-startup> 27 </servlet> 28 29 <servlet-mapping> 30 <servlet-name>spring</servlet-name> 31 <url-pattern>/</url-pattern> 32 </servlet-mapping> 33 34 <servlet-mapping> 35 <servlet-name>default</servlet-name> 36 <url-pattern>*.jpg</url-pattern> 37 </servlet-mapping> 38 <servlet-mapping> 39 <servlet-name>default</servlet-name> 40 <url-pattern>*.png</url-pattern> 41 </servlet-mapping> 42 <servlet-mapping> 43 <servlet-name>default</servlet-name> 44 <url-pattern>*.js</url-pattern> 45 </servlet-mapping> 46 <servlet-mapping> 47 <servlet-name>default</servlet-name> 48 <url-pattern>*.css</url-pattern> 49 </servlet-mapping> 50 51 </web-app>
这里需要注意的是下面的这个代码,如果你的DispatcherServlet拦截 *.do这样的URL,就不存在访问不到静态资源的问题。如果你的DispatcherServlet拦截“/”,拦截了所有的请求,同时对*.js,*.jpg的访问也就被拦截了。就相当于你的css,js,jpg,png文件等信息不能够显示,这是个很大的问题。
<servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:config/sping.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
分析原因:<servlet-mapping>的<url-pattern>/</url-pattern>把所有的请求都交给spring去处理了,而所有available的请求url都是在Constroller里使用类似@RequestMapping(value = "/login/{user}", method = RequestMethod.GET)这样的注解配置的,这样的话对js/css/jpg/gif等静态资源的访问就会得不到。
解决方案有三个,其中一个是在web.xml文件中加入下面代码,将你在jsp文件中用到的所有不能显示的信息都以这样的格式写入,就好了,或者你就使用<url-pattern>*.do</url-pattern>这样的形式来接受前端界面传到后台的url。就不存在这种问题。
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.png</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping>
这个是我看一个大神博客总结的,下面是他的博客地址
http://blog.csdn.net/u012730299/article/details/51872704
2:sping.xml文件,这个文件名我起错了,应该是spring-mvc.xml,不过别介意这些细节
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:task="http://www.springframework.org/schema/task" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 引入属性文件 --> <context:property-placeholder location="classpath*:config/db.properties" ignore-unresolvable="true" /> <!-- 自动扫描(自动注入) --> <context:component-scan base-package="com.ttms.service"/> <context:component-scan base-package="com.controller"/> <!-- 开启注解//该配置项其实也包含了自动注入上述processor的功能,因此当使用<context:component-scan/>后,即可将<context:annotation-config/>省去 <context:annotation-config /> --> <!-- 一、使用数据库连接池注册数据源,引入相关的配置文件 --> <import resource="c3p0.xml"/> <!-- 二、创建mybatis会话工厂 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="mapperLocations" value="classpath:com/ttms/mybatis/mapper/*Mapper.xml"></property> </bean> <!-- 注册接口类的bean,使得程序中可以用注解方式获取 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.ttms.mybatis.mapper" /> </bean> <!--事务管理器类--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--内部视图解析器,JSP与JSTL模板 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--指定视图渲染类 --> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <!--自动添加到路径中的前缀 --> <property name="prefix" value="/login/" /> <!--自动添加到路径中的后缀 --> <property name="suffix" value=".jsp" /> <!--设置所有视图的内容类型,如果视图本身设置内容类型视图类可以忽略 --> <property name="contentType" value="text/html;charset=UTF-8" /> </bean> </beans>
3:c3p0.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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 一、使用c3p0连接池注册数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 基础配置 --> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="driverClass" value="${jdbc.driver}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <!-- 关键配置 --> <!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 --> <property name="initialPoolSize" value="${c3p0.initialPoolSize}"></property> <!--连接池中保留的最小连接数。Default: 2 --> <property name="minPoolSize" value="${c3p0.minPoolSize}"></property> <!--连接池中保留的最大连接数。Default: 15 --> <property name="maxPoolSize" value="${c3p0.maxPoolSize}"></property> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --> <property name="acquireIncrement" value="${c3p0.acquireIncrement}"></property> <!-- 性能配置 --> <!-- 控制数据源内加载的PreparedStatements数量。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 --> <property name="maxStatements" value="${c3p0.maxStatements}"></property> <!-- maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 --> <property name="maxStatementsPerConnection" value="${c3p0.maxStatementsPerConnection}"></property> <!--最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --> <property name="maxIdleTime" value="${c3p0.maxIdleTime}"></property> <property name="acquireRetryAttempts" value="${c3p0.acquireRetryDelay}"></property> <property name="autoCommitOnClose" value="${c3p0.autoCommitOnClose}"></property> </bean> </beans>
4:db.properties文件,这个文件的创建可以可以用记事本创建,把后缀名更改就可以了。
#DB login parameters jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ttms?useUnicode=true&characterEncoding=utf-8&useSSL=true jdbc.username=root jdbc.password=zongjin123 #pool parameters c3p0.initialPoolSize=16 c3p0.minPoolSize=15 c3p0.maxPoolSize=50 c3p0.maxIdleTime=6000 c3p0.acquireIncrement=5 c3p0.acquireRetryAttempts=3 c3p0.acquireRetryDelay=500 c3p0.autoCommitOnClose=false c3p0.checkoutTimeout=10000 c3p0.idleConnectionTestPeriod=600 c3p0.maxStatements=100 c3p0.maxStatementsPerConnection=5 c3p0.numHelperThreads=3 c3p0.testConnectionOnCheckin=false
有一个坑就是jdbc.username这个值指的是Mysql中的Username,我一开始在纠结是不是Connection Name浪费了很长时间,我真是个傻逼,现在也没搞清这个Connection Name有啥用,谁知道告诉我.
5.log4j2.xml这个是日志文件,个人觉得加不加无所谓,
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="off" monitorInterval="1800"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
基本的配置文件就这么多,然后看Mybatis的配置,看我项目的结构,在com.ttms.mybatis.mapper的包下先创建UserDAO接口,UserDAOMapper.xml相当于实现了这个接口
6.接口UserDAO
package com.ttms.mybatis.mapper; import java.util.List; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import com.ttms.Model.*; @Repository public interface UserDAO { //@Param("aaa") String name;作用是给参数命名,名称就是参数的名称 //取全部用户 + 分页 + 按条件匹配 public List<Employee> getAllUsers(@Param("skip") int skip,@Param("size") int size, @Param("search_name") String search_name, @Param("search_account") String search_account); //用户数量 public int getCount(@Param("search_no") String search_no, @Param("search_account") String search_account); //添加用户 public int addUser(User user); public int addEmployee(Employee emp); //更新 public int updateUser(Employee user); //删除 public int deleteUserById(int id); //public User chack_login(@Param("emp_no") String emp_no,@Param("emp_ps") String emp_ps); public User chack_name(@Param("emp_no") String emp_no); }
7:UserDAOMapper.xml中的id指的是UserDAO中的接口函数名,其他的属性看下边的注释
<?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="com.ttms.mybatis.mapper.UserDAO"> <!-- parameterType:是传入参数 resultType:传出参数 id:调用函数名 --> <!-- 查询用户的登录的用户名和密码是否正确 --> <select id = "chack_name" parameterType = "String" resultType = "com.ttms.Model.User"> select * from user where emp_no like #{emp_no} </select> <!--新增用户 --> <insert id="addEmployee" parameterType="com.ttms.Model.Employee"> insert into Employee(emp_no,emp_name,emp_tel_num,emp_addr,emp_email) values(#{emp_no},#{emp_name},#{emp_tel_num},#{emp_addr},#{emp_email}) </insert> <insert id = "addUser" parameterType = "com.ttms.Model.User"> insert into User(emp_no,emp_pass) values(#{emp_no},#{emp_pass}) </insert> <!-- 更新用户 --> <update id="updateUser" parameterType="com.ttms.Model.Employee"> update employee set emp_no=#{emp_no},emp_name=#{emp_name},emp_tel_num=#{emp_tel_num},emp_addr=#{emo_addr},emp_email=#{emp_email} where emp_id=#{emp_id} </update> <!--删除用户 --> <delete id="deleteUserById" parameterType="int"> delete from employee where emp_id=#{emp_id} </delete> </mapper>
8:User类
package com.ttms.Model; public class User { private String emp_no; private String emp_pass; private int type; private String head_path; public String getEmp_no() { return emp_no; } public void setEmp_no(String emp_no) { this.emp_no = emp_no; } public String getEmp_pass() { return emp_pass; } public void setEmp_pass(String emp_pass) { this.emp_pass = emp_pass; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getHead_path() { return head_path; } public void setHead_path(String head_path) { this.head_path = head_path; } }
9:定义service层的接口,虽然是实现了登录功能,但里边还有一些其他了函数功能。
package com.ttms.service; import java.util.List; import org.springframework.stereotype.Repository; import com.ttms.Model.*; @Repository public interface IorderServer { /** * 获取用户 + 分页 + 筛选 * @param pageNo 页码 * @param size 页的大小 * @param search_name 按姓名匹配 * @param search_account 按账号匹配 * @return */ public List<Employee> getAllUsers(int pageNo, int size, String search_name, String search_account); /** * 用户数量 * @return */ public int getCount(String search_name, String search_account); /** * 新增用户 * @param user * @return */ public Boolean addEmployee(Employee emp); public Boolean addUser(User user); /** * 更新用户 * @param user * @return */ public int updateUser(Employee user); /** * 删除用户 * @param id * @return */ public int deleteUserById(int id); public User login(String name, String password); public Boolean chack_zhuce(String name); }
10:EmployeeTest实现IorderServe接口,其中用到了注解@Autowired来自动装配UserDAO接口,这些注解的具体使用,我会在下一的博客中总结。
package com.ttms.service; import java.util.List; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.ttms.Model.Employee; import com.ttms.Model.User; import com.ttms.mybatis.mapper.UserDAO; //@Service("UserService") 注解用于标示此类为业务层组件,在使用时会被注解的类会自动由 //spring进行注入,无需我们创建实例 @Service("IorderServer") public class EmployeeTest implements IorderServer { @Autowired //不用你去实现set和get方法它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作 //@Resource UserDAO userdao;//这里它是一个接口所以不需要去在xml文件中定义属性和对应的值,自动注入userdao 用于访问数据库 public List<Employee> getAllUsers(int pageNo, int size, String search_name, String search_account) { // TODO Auto-generated method stub return null; } public int getCount(String search_name, String search_account) { // TODO Auto-generated method stub return 0; } public Boolean addUser(User user) { // TODO Auto-generated method stub int flg = userdao.addUser(user); if(flg == -1) return false; return true; } public Boolean addEmployee(Employee emp) { int flg =userdao.addEmployee(emp); if(flg == -1) return false; return true; } public int updateUser(Employee user) { // TODO Auto-generated method stub return 0; } public int deleteUserById(int id) { // TODO Auto-generated method stub return 0; } public User login(String emp_no, String emp_ps) { // TODO Auto-generated method stub System.out.println("进入了test1"); User user = userdao.chack_name(emp_no); System.out.println("进入了test2"); if(user != null) { if(user.getEmp_no().equals(emp_no) && user.getEmp_pass().equals(emp_ps)) { return user; } } return null; } public Boolean chack_zhuce(String search_no) { // TODO Auto-generated method stub User user = userdao.chack_name(search_no); if(user != null) { return true;//表示重名 } return false;//表示未重名 } }
11.控制器UserController,通过注解@RequestMapping("/login")和@RequestMapping("/save")来获取前端页面form中发过来的aciton="${pageContext.request.contextPath}/login/save",其中
${pageContext.request.contextPath}的作用是取出部署的应用程序名,这样不管如何部署,所用路径都是正确的。
package com.controller; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.json.JSONArray; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.RedirectView; import com.ttms.Model.*; import com.ttms.service.*; //method = RequestMethod.POST @Controller @RequestMapping("/login") //在默认情况下springmvc的实例都是单例模式,所以使用scope域将其注解为每次都创建一个新的实例 @Scope("prototype") public class UserController{ //自动注入业务层的userService类 @Autowired IorderServer ttms; @RequestMapping(value="/save",method = RequestMethod.POST) public ModelAndView chack_login(String emp_no,String emp_ps,ModelAndView mv,HttpSession session){ User user = ttms.login(emp_no, emp_ps); if(user!=null){//管理员登陆 if(user.getType() == 1) { //转发到main请求 System.out.println("进入了1"); mv.setViewName("index"); mv.addObject("user", user); } //普通用户登陆 else if(user.getType() == 0) { mv.setViewName("Emp_index"); mv.addObject("user",user); } else { //登录失败,设置失败信息,并调转到登录页面 mv.addObject("message","登录名和密码错误,请重新输入"); mv.setViewName("login"); } } return mv; } }
12.login.jsp,我用的是bootstrap框架,你们用的话可能不会显示出来效果,这里只看功能。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page isELIgnored="false"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <script src="bootstrap.min.js"></script> <script src="jquery-3.1.1.min.js"></script> <link rel="stylesheet" href="css/bootstrap.min.css"/> <link rel="stylesheet" href="css/login.css" /> <title></title> </head> <body> <div id="back" > <div id="logo"><img src="img/login/logo.png" /></div> <div id="lg"> <label id="lname">${message}</label> <div id="lg1"><p><span>用户登录</span></p></div> <form action="${pageContext.request.contextPath}/login/save" method="post"> <label for="emp_no" class="col-sm-2 control-lable" style="color: white;">账号:</label> <div class="clol-sm-4"> <input type="text" style="color: black;" class="form-control" id="emp_no" name="emp_no" placeholder="请输入大小写字母和数字,长度6-20位" pattern="[a-zA-Z0-9]{4,20}" required="required" oninvalid="setCustomValidity('请输入大小写字母和数字,长度4-20位!')" oninput="setCustomValidity('')" > </div> <label for="emp_ps" class="col-sm-2 control-lable" style="color: white;">密码:</label> <div class="clol-sm-4"> <input type="text" style="color: black;" class="form-control" id="emp_ps" name="emp_ps" placeholder="请输入大小写字母和数字,长度6-20位" pattern="[a-zA-Z0-9]{4,20}" required="required" oninvalid="setCustomValidity('请输入大小写字母和数字,长度4-20位!')" oninput="setCustomValidity('')" > </div> <div class="form-group"> <div class="col-sm-2 control-label" style="color:red;font-weight: bold;"></div> <div class="col-sm-4"> <button type="submit" class="btn btn-success">登录</button> </div> </div> </form> <div class="col-sm-4"> <a href="./zhuce.jsp" style="color: white;">注册</a> </div> </div> </div> <script src="bootstrap.min.js"></script> <script type="text/javascript"> </script> </body> </html>
13.index.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ page isELIgnored="false" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title>TTMS</title> <link rel="stylesheet" href="layui/css/layui.css"> </head> <body class="layui-layout-body"> <p>管理员${user.emp_no}登录成功</p> </body> </html>
14.Emp_index.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ page isELIgnored="false" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title>TTMS</title> <link rel="stylesheet" href="layui/css/layui.css"> </head> <body class="layui-layout-body"> <p>普通用户${user.emp_no}登录成功</p> </body> </html>
15.数据库的user表
16:下一篇博客讲一下controller如何向前端jsp页面发送数据,以及jsp界面如何接受数据