57.java基础——零基础入门之SpringMVC

版权声明:版权归零零天所有,若有转载请注明出处。 https://blog.csdn.net/qq_39188039/article/details/86620610

SpringMVC介绍


介绍
Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。从而在使用Spring进行WEB开发时,可以选择使用Spring的SpringMVC框架来开发。

MVC的概念
MVC是一种分层的设计思想,Model-View-Controller 模型-视图-控制器。

在这里插入图片描述
这种框架模式,体现了分层的设计理念,好处就是:第一,利于团队分工,每个人专注于某一个层的开发。第二,便于工程项目管理。第三,降低层与层之间的依赖。

目前常见的MVC框架:
1.Struts2
2.SpringMVC
在这里插入图片描述
最经典的MVC分层架构是:
jsp+servlet+javabean

但是这种经典的MVC架构也存在一定的问题和局限性,主要是体现在servlet上。所以后来在技术的发展过程中,出现了很多MVC框架,比如Struts1,webwork,Struts2,SpringMVC等。这些MVC框架目的都是帮助程序员更快速地开发JavaEE程序。

Servlet技术存在的问题
1.不适合大型项目的开发,配置一个Servlet至少要在web.xml里配置8行,200个—1600行,造成维护和修改的难度相当大,不适合团队开发,如果不协调好,非常容易出现冲突。
2.request.getParamter(“参数名”),造成代码繁琐,request.getParameter()=参数值(String),得进行类型的转换
3.public class HomeServlet extends HttpServlet{

doGet(res,req){

Request.getParameter()=参数值
if(参数值=add)执行增加的方法;
If(……=delete)执行删除的方法;

}

}
比如做增删改查4个业务操作的话,要么建4个servlet,要么doGet()写4个方法
4.Servlet是一个有严重的容器依赖性类,主要体现在单元测试上,意味着每调试一次,就要启动一次服务器,拉长调试周期。

代码重构思路

Public class UserController{
 
Public void userLogin(){
 
}
 
Public void userRegister(){
 
}
 
}

用户发送请求——http://localhost:8080/项目名/login 就执行 userLogin()的方法
http://localhost:8080/项目名/register 就执行userRegister()的方法

SpringMVC整体架构图
在这里插入图片描述

入门案例


案例说明:
用户发送一个请求,http://localhost:8080/项目名/login.action 就是执行
Controller类里的userLogin()方法
开发步骤:
1.创建一个web工程
2.引入SpringMVC依赖的jar包
3.在web.xml里配置SpringMVC的核心入口类,DispatcherServlet
4.开发控制层Controller
5.建立核心配置文件,配置注解驱动,配置包扫描
6.项目的部署和测试
知识点:
1.依赖的jar包

com.springsource.javax.validation-1.0.0.GA.jar
com.springsource.org.apache.commons.logging-1.1.1.jar
commons-fileupload-1.2.2.jar
commons-io-2.0.1.jar
hibernate-validator-4.1.0.Final.jar
jackson-core-asl-1.9.13.jar
jackson-mapper-asl-1.9.13.jar
jstl-api-1.2.jar
jstl-impl-1.2.jar
log4j.jar
slf4j-api-1.5.8.jar
slf4j-log4j12.jar
spring-aop-3.2.2.jar
spring-aspects-3.2.2.jar
spring-beans-3.2.2.jar
spring-context-3.2.2.jar
spring-context-support-3.2.2.jar
spring-core-3.2.2.jar
spring-expression-3.2.2.jar
spring-web-3.2.2.jar
spring-webmvc-3.2.2.jar
standard-1.1.2.jar

2.核心入口类DistpacherServlet的继承树结构:
HttpServlet——HttpServletBean——FrameworkServlet——DispathcerSerlvet
3.核心配置文件的规范:
命名规范:在web.xml里配置的Servlet的名字±servlet.xml 本例中 smvc-servlet.xml
存放位置:WEB-INF目录下
4.核心配置文件里的内容:
需要配置注解驱动,使得注解生效,

 <!-- 配置注解驱动 -->                                      
 <mvc:annotation-driven></mvc:annotation-driven>
 

知识点:
<mvc:annotation-driven /> 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的。
并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。

通过配置包扫面的方式,在加载Controller的bean,这样更通用,更简单,只需要配置一次就可以。

 <!-- 配置Controller的bean,通过宝扫描的方式来配-->
  <context:component-scan base-package="/controller"></context:component-scan> 

5.用的注解
@Controller的作用:标识当前类是Controller类,并且在容器进行包扫描的时候,让当前类进行bean的加载
@RequsetMapping(请求路径)作用:把请求路径和执行方法建立映射关系,这样用户在输入相应的访问路径时,就直接调用对应的方法。

页面参数封装


需求说明:建一个用户注册页面,提交用户名、年龄、生日信息,然后提交到后台Controller,进行参数解析

如何拿到HttpServletRequset对象?
遇到的第一个问题,但是针对目前的结构,没有HttpRequest对象了,那怎么拿参数啊?而且没有Requset对象,请求的URI也拿不到了。怎么解决呢?

public class UserController {
 
 
@RequestMapping("/login.action")
public void userLogin(){
 
System.out.println("用户登录");
}
 
@RequestMapping("/register.action")
public void userRegister(){
System.out.println("用户注册");
}
}

解决办法:在被调用的方法形参里,声明HttpServletRequest对象即可

如何取得页面参数
当参数多的时候,还是得多次调用request.getParameter()方法,SpringMVC是怎么解决呢?
要啥参数,就在被调用的方法里,写什么参数
@RequestMapping("/register.action")
public void userRegister(String name,int age){
System.out.println(name+":"+age);
}
post提交的中文乱码解决
在web.xml里配置:

<!-- 中文乱码过滤器 -->
<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>        

思考:SpringMVC能设计成这种效果,要什么,就在方法的形参里写什么,然后就有什么,比如HttpServletRequest对象,比如页面的参数。这样给编程人员带来什么好处呢?有什么重要意义呢?
1.参数的获取变得非常简单,不用调用任何方法,就能拿到参数,代码少了,更爽了。大大提高了开发效率。
2.对参数或对象的控制粒度很细,想要什么,就有什么,不用的通通没有,比如HttpServletRequest对象,我不要就没有
3.参数的共享范围是方法级别的,即方法之间的参数值互不影响,参数只被当前被调用的方法所独享。

特殊类型参数封装


封装日期类型时,页面报了400错误是啥意思?
HTTP Status 400 -
记住:这个错误代表类型转换时出错。

SpringMVC默认地日期格式是?
yyyy/MM/dd

如何更改日期格式?
1.利用@DateTimeFormat()注解
控制层代码:

@RequestMapping("/register.action")
public String userRegister(String name,int age,
@DateTimeFormat(pattern="yyyy-MM-dd")Date birthday){
System.out.println(name+":"+age+":"+birthday);
return "success";
 
}
 

2.通过注册一个自定义的日期格式类型转换器
控制层代码:

@InitBinder  //这个注解的作用就是注册一个自定义的日期格式类型转换器
public void InitBinder (ServletRequestDataBinder binder){
binder.registerCustomEditor(
java.util.Date.class, 
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}

注意:这两种方法,生效的范围不同
注解方式的生效范围:仅对被调用的方法里date日期生效
转换器的生效范围:一个Controller类里的所有方法的date日期生效

如何把参数封装到javabean里?
非常简单:
第一步,把javabean写好,注意私有属性要和页面的参数名要一致,并且要添加get、set方法
第二步,在方法的形参里声明这个javabean,框架自动帮你封装好

关联对象如何封装?
比如User类里还有一个UserInfo类,对于这种关联对象,SpringMVC也能自动封装
注意在jsp参数名的写法
jsp代码:

<form action="${pageContext.request.contextPath }/register.action" method="post">
用户名:<input type="text" name="name"/>
年龄:<input type="text" name="age"/>
生日:<input type="text" name="birthday"/>
电话:<input type="text" name="userInfo.phone"/>
邮箱:<input type="text" name="userInfo.email"/>
<input type="submit" value="提交"/>
 

checkbox复选框,传递过来的应该是一个List集合,如何封装?
控制层代码:

@RequestMapping("/register.action")
public String userRegister(String[] ids){
for(String s:ids)System.out.println(s);
return "success";
 
}

jsp代码:
复选框:

<input type="checkbox" name="ids" value="1"/>
<input type="checkbox" name="ids" value="2"/>
<input type="checkbox" name="ids" value="3"/>
<input type="checkbox" name="ids" value="4"/>

视图解析器


需求说明,因为在项目中,页面都是放在WEB-INF目录下,不能直接访问,所以通过发送 http://localhost:8080/项目名/login.action 执行后台的userLogin()方法,然后通过这个方法来转向前台页面

解决办法1:引入HttpServletRequest和HttpServletResponse对象

@RequestMapping("/login.action")
 
public void userLogin(HttpServletRequest req,HttpServletResponse res){
 
System.out.println("用户登录");
try {
req.getRequestDispatcher("/WEB-INF/pages/userRegister.jsp").forward(req, res);
 
} catch (Exception e) {
 
e.printStackTrace();
}
}

这种方式虽然可以实现,但是麻烦。

解决办法2:引入视图解析器

@RequestMapping("/login.action")
public String userLogin(){
 
return "userRegister";//视图逻辑名
 
}

视图解析器的工作原理:根据配置的前缀名 +视图逻辑名+后缀名 进行拼串,拼成一个完整的页面路径,继而转向相应的页面。
这样带来的好处:在核心配置文件里,只需要配置一次视图解析器,以后我们只需要在Controller里写返回的视图逻辑名就可以了。代码更少了,结构更通用了。

视图解析器在核心配置文件里的配置:

 <!-- 配置内部资源视图解析器 -->                        
     <bean id="jspViewResolver"  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <!-- 配置视图前缀名和后缀名 -->
     <property name="prefix" value="/WEB-INF/pages/"></property>
     <property name="suffix" value=".jsp"></property>
     </bean>

标红的地方,名字是固定的,不要写错。Prefix——前缀名 suffix——后缀名

向页面传递数据+JSTL解析数据


如何从控制层传递数据呢?
1.可以利用HttpServletRequest来传值

@RequestMapping("/passValue.action")
public String passValue(HttpServletRequest req){
req.setAttribute("msg", "hello SpringMVC");
 
return  "success";
}

2.利用一个新的对象 Model 来传值,这种方式是今后最常用的,要记住。Model是一个接口,默认地实现类BindingAwareModelMap,实际上是个map结构(linkedHashMap)

@RequestMapping("/passValue.action")
public String passValue(Model model){
model.addAttribute("msg", "hello Rod Johnson!");
 
return  "success";
}
 

传递User对象,页面如何解析数据

第一种方式:
java代码:

@RequestMapping("/passValue.action")
public String passValue(Model model){
User user=new User();
user.setName("Thomes kyte");
user.setAge(10);
 
UserInfo userInfo=new UserInfo();
userInfo.setPhone("123124");
user.setUserInfo(userInfo);
 
model.addAttribute("param",user);//这种传值方式导致页面取值时代码比较麻烦
 
 
return  "userInfo";
}

页面代码:

用户名:<c:out value="${requestScope.param.name }"/><br>
年龄:<c:out value="${requestScope.param.age }"/><br>
电话:<c:out value="${requestScope.param.userInfo.phone }"/><br>

第二种方式:
java代码:

@RequestMapping("/passValue.action")
public String passValue(Model model){
User user=new User();
user.setName("Thomes kyte");
user.setAge(10);
 
UserInfo userInfo=new UserInfo();
userInfo.setPhone("123124");
user.setUserInfo(userInfo);
 
model.addAttribute(user);//直接传User对象
 
 
return  "userInfo";
}

页面代码:

用户名:<c:out value="${user.name }"/><br>
年龄:<c:out value="${user.age }"/><br>
电话:<c:out value="${user.userInfo.phone }"/><br>

传递一个集合
java代码:

@RequestMapping("/passValue.action")
public String passValue(Model model){
List<User> list=new ArrayList<User>();
User u1=new User();
u1.setName("宋江");
User u2=new User();
u2.setName("李逵");
list.add(u1);
list.add(u2);
model.addAttribute("list",list);
 
return  "userInfo";
}

页面代码:

<c:forEach items="${list }" var="user">
<tr>
姓名:${user.name }
</tr>
</c:forEach>

传递单个对象 以及 集合对象,用EL来解析
单个对象Jsp代码:

用户名:${requestScope.user.name }
密码: ${requestScope.user.age }

集合对象Jsp代码:

解析到的参数:${ msg}
用户名:${requestScope.list[0].name }
密码: ${requestScope.list[0].age }
<br>
用户名:${requestScope.list[1].name }
密码: ${requestScope.list[1].age }

@RequestParam+结果转发


如果页面参数名和后台方法里的形参名不一致时,不能自动封装,怎么解决?
利用RequsetParam(value=“页面参数名”)来建立映射关系

@RequestMapping("/userRegister.action")
public String userRegister(@RequestParam(value="name")String userName,int age){
System.out.println(userName+":"+age);
 
return "success";
}

比如有的用户在填表单时,没有写年龄,传过来的是null,结果报400错误,因为null值是不能转换为整形的,所以有个需求—如果用户没有填年龄,则都默认为0岁。
用注解:@RequestParam(defaultValue="0")很简单就可以实现:

@RequestMapping("/userRegister.action")
public String userRegister(@RequestParam(value="name")String userName,
@RequestParam(defaultValue="0")int age){
 
System.out.println(userName+":"+age);
 
return "success";
}

如何从一个Controller转向另一个Controller
1.第一种方式,引入HttpServletRequest 和 response对象,但是比较麻烦

/*
 * 结果转发:一个controller转向另一个Controller
 */
@RequestMapping("/forwardA.action")
public void forword_A_Controller(HttpServletRequest req,HttpServletResponse res) throws Exception, IOException{
System.out.println("地瓜地瓜,我是土豆");
req.getRequestDispatcher("/forwardB.action").forward(req, res);
 
}
@RequestMapping("/forwardB.action")
public String forword_B_Controller(){
System.out.println("我是地瓜,我是地瓜");
return "success";
}

2.第二种方式,利用视图解析器,一句return就搞定 关键字:forward

@RequestMapping("/forwardA.action")
public String forword_A_Controller() {
System.out.println("地瓜地瓜,我是土豆");
return "forward:/forwardB.action";
 
}
@RequestMapping("/forwardB.action")
public String forword_B_Controller(){
System.out.println("我是地瓜,我是地瓜");
return "success";
}

如何从一个Controller重定向另一个Controller 关键字:redirect

@RequestMapping("/forwardB.action")
public String forword_B_Controller(){
System.out.println("我是地瓜,我是地瓜,番茄你在哪?");
return "redirect:/forwardC.action";
}
/*
 * 这个重定向的Controller
 */
@RequestMapping("/forwardC.action")
public String forward_C_Controller(){
System.out.println("我是番茄,已收到");
return "success";
}

SpringMVC的核心配置文件一定要放在WEB-INF目录下吗?
在web.xml里,更改一下配置信息即可:

<servlet>
 <servlet-name>smvc</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 <!-- 更改核心配置文件的加载路径,注意,指定的文件名要和实际的文件名一致 -->
         <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:smvc-servlet.xml</param-value>
          </init-param>
 </servlet>

RESTful架构设计风格+ @PathVariable


@PathVariable 绑定URI 模板变量值,支持RESTful架构
RESTful架构设计风格,凡是简洁的,有分层的、便于扩展的设计风格都可以叫RESTful,对于web开发来说,最典型的RESTful设计改变,就是体现在咱们的Get请求上。

REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。

Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一任主席。所以,他的这篇论文一经发表,就引起了关注,并且立即对互联网开发产生了深远的影响。

@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上
形成RESTful形式,这将是未来的发展趋势。它更加简洁,安全。强化URL GET访问方式。

控制层代码:

@RequestMapping("/restful/{name}/{age}")
public void restfulTest(@PathVariable(value="name") String name,
@PathVariable(value="age")Integer age){
System.out.println(name+":"+age);
System.out.println("收到");
 
}

浏览器访问的URL
http://localhost:8090/项目名/tom/23

上一篇 56…java基础——零基础入门之Mybatis进阶

猜你喜欢

转载自blog.csdn.net/qq_39188039/article/details/86620610
今日推荐