1、什么是springMVC
springMVC基于java实现的MVC的设计模式,通过把model,view,controller分离,将web层进行解耦,将复杂的逻辑清晰化,简化代码开发,方便开发人员之间的配合.
2、Spring MVC框架特点
3、spring MVC的请求处理流程
【1、用户向服务器发出请求,请求被SpringMVC 前端控制器 DispatcherServlet 捕获;
2、DispatcherServlet收到请求调用HandlerMapping处理器映射器()。
3、DispatcherServlet 对请求 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截 器),最后以 HandlerExecutionChain 对象的形式返回;
4、DispatcherServlet 根据获得的 Handler,选择一个合弁的 HandlerAdapter;(附注:如果成功获得HandlerAdapter 后,此时将开始执行拦截器的 preHandler(true或者false) 方法)
5、提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller)。 在填充 Handler的 入参过程中,根据你的配置,SpringMVC 将帮你做一些额外的工作:
5.1 HttpMessageConveter: 将请 求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息。
5.2 数据转换:对请求消息进行数据转换。如 String 转换成 Integer、Double 等。
5.3 数据根式化:对请求消息进行数据格式 化。 如将字符串转换成格式化数字或格式化日期等。
5.4数据验证: 验证数据的有效性(长度、格式 等),验证结果存储到 BindingResult 或 Error 中。
6、Handler 执行完成后,向HandlerAdapte返回一个 ModelAndView 对象;
7、HandlerAdapter将根据返回的 ModelAndView(必须是已经注册到 SpringMVC 容器中的ViewResolver)返回给 DispatcherServlet;
8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。】
4、Spring MVC体系结构介绍:
5、使用SpringMVC实现页面输出
步骤:
1、下载jar文件并导入工程
spring-web-3.2.13.RELEASE.jar
spring-webmvc-3.2.13.RELEASE.jar
2、配置文件
在web.xml中配置Servlet
创建Spring MVC的配置文件
3、创建Controller-处理请求的控制器
BeanNameUrlHandlerMapping
4、创建View-jsp
5、部署运行
//导入依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<spring.version>3.2.4.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
</dependencies>
方法一:使用配置文件的方式
web.xml配置
spring-mvc.xml
创建Controller:继承AbstractController,重写handleRequestInternal()
方法二:使用注解的方式
web.xml配置
spring-mvc.xml
创建Controller @Controller @RequestMapping
注释:1、@Controller:标注一个普通的JavaBean成为可以处理请求的控制器 @RequestMapping:通过请求URL进行映射
2、类名前面也可以加@RequestMapping(),如@RequestMapping(“/user.do”),结合上述的方法,路径就变为了/user/login.do,但这种方式容易发生404路径错误
spring mvc 零散知识点
1.项目添加字符转码的配置
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.项目controller 省去了.do的操作 具体配置web.xml配置代码
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
代码上的配置
@RequestMapping(value = “/show”, method = RequestMethod.POST)
3.方法中转发或重定向的写法
// return "redirect:/show.jsp";
// return "forward:/show.jsp"; ==return "/show";
注意事项
.jsp必须在页面名称的后面,否则404
4.springmvc对jsp页面的静态资源做了权限的限制, 直接在jsp页面中访问静态资源出现404的问题
<mvc:resources location="/static/" mapping="/static/**"/>
5.springmvc的局部异常的配置, 特定只能在当前配置的类中生效.
5.1实现HandlerExceptionResolver接口
implement HandlerExceptionResolver
重写方法
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object arg2, Exception ex) { System.out.println("局部异常处理方法1:" + ex); return new ModelAndView("/err"); }
5.2使用注解的方法
@ExceptionHandler
public ModelAndView resolveException(Exception ex){
System.out.println("局部异常处理方法2:" + ex);
return new ModelAndView("/err");
}
6.全局异常配置,对所有异常进行统一处理
<!-- 全局异常配置 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.RuntimeException">err</prop>
</props>
</property>
</bean>
7.整合项目
与之前不同点:web.xml代码配置
<!-- 加载spring-mybatis的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mybatis.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
8.rest风格的url参数参数
地址栏风格://http://localhost:8080/ssm/show/1/admin
@RequestMapping(value = "/show/{paramId}/{paramName}", method = RequestMethod.GET)
public String view(@PathVariable("paramId") Integer id,@PathVariable("paramName") String name, HttpServletRequest request){
System.out.println("页面的数据:"+id+"\t"+name);
List<Dept> list = deptService.findDeptList();
for (Dept dept : list) {
if(dept.getId()==id){
request.setAttribute("dept", dept);
break;
}
}
return "/ok";
}
9、@DateTimeFormat
将后台的date类型的数据执行格式化操作
10.jsr 303的验证
10.1添加依赖:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.1.GA</version>
</dependency>
10.2验证规则
@NotNull(message = “用户名不能为空!”)
@Length(min = 6, max = 20, message = “用户名的长度必须在6-20之间”)
10.3在验证的对象前添加@Valid 注解
BindingResult 用于检测验证中是否存在错误提示,有错误提示跳转到提交页面显示错误信息
10.4显示错误信息
11.文件上传
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8" />
<property name="maxUploadSize" value="5000000" />
</bean>
表单
<form action="doupdate" method="post" enctype="multipart/form-data">
<p>
<input type="text" name="name">
</p>
<p>
<input type="file" name="file">
</p>
<input type="submit" value="上传">
</form>
控制器
@RequestMapping(value = "/doupdate", method = RequestMethod.POST)
public String myupload(HttpServletRequest request, @RequestParam("file") MultipartFile file, String name) {
System.out.println(name);
if (file != null) {
// 上传的文件路径
// c://mydoc
String path = request.getSession().getServletContext().getContextPath();
// a.txt
String filename = file.getOriginalFilename();
// c://mydoc/a.txt
File myFile = new File(path, filename);
System.out.println(myFile.getAbsolutePath());
if (!myFile.getParentFile().exists()) {
// 创建文件夹
myFile.getParentFile().mkdir();
}
try {
// 开始文件上传
file.transferTo(myFile);
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return "ok";
}
12.@ModelAttribute 从后端向前端页面控件中绑定数据
13.页面获取采用springmvc的标签, 定位到modelAttribute中的对象名称
标签 path属性 属性的值必须是java中属性名称, 就能完成后台模型数据绑定到前台控件
//控制器
//从后端向前端页面控件中绑定数据@ModelAttribute("user")
@RequestMapping(value = "/toupdate", method = RequestMethod.GET)
public String toupdate(@ModelAttribute("user") User user) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
user.setId(1);
user.setName("张三");
user.setAddress("徐州");
user.setSex(0);
user.setAge(20);
try {
user.setBirthday(sdf.parse("2000-01-01"));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Dept d = new Dept();
d.setDid(1);
d.setDname("开发");
user.setDept(d);
return "update";
}
//前端:
<%--
spring表单
<fm:form action="doupdate" method="post" modelAttribute="user">
编号:<fm:input path="id" />
<br />
名称:<fm:input path="name" />
<br />
年龄:<fm:input path="age" />
<br />
<fm:radiobutton path="sex" value="0" />男
<fm:radiobutton path="sex" value="1" />女<br />
地址:<fm:textarea path="address" /><br />
部门:<fm:input path="dept.did" /><fm:input path="dept.dname" /><br />
生日:<fm:input path="birthday"/>
<input type="submit" value="修改" />
<div style="color: red;">
<fm:errors path="*" />
</div>
</fm:form>
--%>
普通表单
<form id="user" action="doupdate" method="post">
编号:<input id="id" name="id" type="text"/>
<br />
名称:<input id="name" name="name" type="text"/>
<br />
年龄:<input id="age" name="age" type="text"/>
<br />
<input id="sex1" name="sex" type="radio" value="0"/>男
<input id="sex2" name="sex" type="radio" value="1"/>女<br />
地址:<textarea id="address" name="address"></textarea><br />
部门:<input id="dept.did" name="dept.did" type="text"/><input id="dept.dname" name="dept.dname" type="text"/><br />
生日:<input id="birthday" name="birthday" type="text" />
<input type="submit" value="修改" />
<div style="color: red;">
</div>
</form>
14、ajax(前端和之前几乎不发生变化,后台变化如下:)
ajax嵌套:
页面:
var auctionHtml="";
$.post("findInTime",null,function(result){
var obj = $.parseJSON(result);
for(var i = 0;i<obj.length;i++){
var g = obj[i];
auctionHtml+=" <ul class=\"rows\">\n" +
" <li><a href=\"国书\" title=\"\">"+g.auctionName+"</a></li>\n" +
" <li>"+g.auctionStartTime+"</li>\n" +
" <li>"+g.auctionEndTime+"</li>\n" +
" <li>"+g.auctionStartPrice+"</li>"+
" <li class=\"borderno blue record\">\n";
$.ajax({
url:"findRecordList",
type:"post",
async:false,//如果不写,下面的数据出不来
data:"id="+g.auctionId,
success:function(result){
var record = $.parseJSON(result);
for(var i = 0;i<record.length;i++){
var r = record[i];
auctionHtml+= "<p>"+r.auctionuser.userName+" "+r.auctionPrice+"</p>\n" ;
}
auctionHtml+="</li>\n";
}
})
auctionHtml+=" <div class=\"cl\"></div>\n" +
" </ul>";
}
$("#saleNow").html(auctionHtml);
});
效果图:
15、验证码
//Number.jsp
<%@ page contentType="image/jpeg"
import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*"
pageEncoding="utf-8"%>
<%!Color getRandColor(int fc, int bc) {//给定范围获得随机颜色
Random random = new Random();
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
%>
<%
//设置页面不缓存
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
// 在内存中创建图象
int width = 60, height = 20;
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
// 获取图形上下文
Graphics g = image.getGraphics();
//生成随机类
Random random = new Random();
// 设定背景色
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
//设定字体
g.setFont(new Font("Times New Roman", Font.PLAIN, 18));
//画边框
//g.setColor(new Color());
//g.drawRect(0,0,width-1,height-1);
// 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到
g.setColor(getRandColor(160, 200));
for (int i = 0; i < 155; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x, y, x + xl, y + yl);
}
// 取随机产生的认证码(4位数字)
String sRand = "";
for (int i = 0; i < 4; i++) {
String rand = String.valueOf(random.nextInt(10));
sRand += rand;
// 将认证码显示到图象中
g.setColor(new Color(20 + random.nextInt(110), 20 + random
.nextInt(110), 20 + random.nextInt(110)));//调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
g.drawString(rand, 13 * i + 6, 16);
}
// 将认证码存入SESSION
session.setAttribute("numrand", sRand);
// 图象生效
g.dispose();
// 输出图象到页面
ImageIO.write(image, "JPEG", response.getOutputStream());
out.clear();
out = pageContext.pushBody();
%>
验证码存在session里的,后面要到session里取出来
jsp页面
16、短消息验证结合Redis存储
1、注册云通信
2、讲本地jar包打入本地仓库里去
命令:
mvn install:install-file -Dfile=sms-java-sdk-2.6.3.jar -DgroupId=com.zb -DartifactId=sms-java-sdk -Dversion=1.0 -Dpackaging=jar -DgeneratePom=true
3、导入依赖
<!--云通信短消息验证-->
<dependency>
<groupId>com.zb</groupId>
<artifactId>sms-java-sdk</artifactId>
<version>1.0</version>
</dependency>
<!--redis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.1.0</version>
</dependency>
4、添加工具类
@Component
public class SMSService {
public void send(String to, String templated, String[]datas){
//https://www.yuntongxun.com/member/main
CCPRestSmsSDK sdk = new CCPRestSmsSDK();
//生产环境请求地址:app.cloopen.com
sdk.init("app.cloopen.com", "8883");//请求端口
//主账号,登陆云通讯网站后,可在控制台首页看到开发者主账号ACCOUNT SID和主账号令牌AUTH TOKEN
sdk.setAccount("8a216da870e2267e01712ff8a629299d", "0a6b572fbe6048519cb0e9ceb653b176");
sdk.setAppId("8a216da870e2267e01712ff8a68029a3");
HashMap result = sdk.sendTemplateSMS(to, templated, datas);
System.out.println(result);
}
//测试
public static void main(String[] args) {
SMSService sms = new SMSService();
int code = (int)(Math.random()*10000);
System.out.println(code);
//templated模板
sms.send("15851997193", "1", new String[]{code+"","1"});
}
}
5、控制器(结合Redis):
@RequestMapping("/sendmsg")
@ResponseBody
public String mySend(String phone ){
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.auth("ok");
int genterCode = (int)(Math.random()*10000);
System.out.println(genterCode);
SMSService sms = new SMSService();
sms.send(phone, "1", new String[]{genterCode+"","1"});
String key = "phone_"+phone;
jedis.set(key,genterCode+"");
jedis.expire(key,60);
return "ok";
}
@RequestMapping("/validate")
@ResponseBody
public String validate(String phone , String inCode,String name, String password, HttpSession session){
Auctionuser auctionuser = as.userLogin(name,password);
session.setAttribute("user",auctionuser);
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.auth("ok");
String key = "phone_"+phone;
if(jedis.exists(key)){
String redisCode = jedis.get(key);
if(auctionuser!=null&&auctionuser.getUserIsadmin()!=1&&redisCode.equals(inCode)){
return "ok";
}else{
return "error";
}
}else{
return "input";
}
}
<script type="text/javascript" src="statics/js/jquery-1.12.4.js"></script>
<script type="text/javascript">
var mytime ;
$(function() {
$("#send").on("click",function(){
var phone = $("#phone").val();
$.post('sendmsg','phone='+phone,function(result){
if(result=="ok"){
mytime=setInterval("mt()",1000);//定时函数,每一秒钟调用mt()
}
});
});
$("#sbt").click(function () {
var phone = $("#phone").val();
var inCode = $("#code").val();
var name = $("#name").val();
var password = $("#password").val();
$.ajax({
url:"validate",
type:"post",
data:"phone="+phone+"&inCode="+inCode+"&name="+name+"&password="+password,
success:function (result) {
if(result=="input"){
$("#smsMsg").html("验证码已超时");
}else if(result=="error"){
$("#smsMsg").html("验证码输入不正确");
}else if(result=="ok"){
location.href="commonAuctionList.jsp";
}
}
});
})
});
var mi=60;
function mt(){//倒计时函数
if(mi!=1){
mi=mi-1;
$("#msg").html(mi+"秒");
}else{
clearInterval(mytime);
mi=60;
$("#msg").html("<input type=\"button\" id=\"send\" value=\"发送\" />");
}
}
</script>