北京尚学堂2020java_SpringMVC第二天
第一节 SpringMVC的响应
使用了SpringMVC之后,servlet只有一个,那就是DispatcherServlet。但它又不是我们声明的,需要在外部声明单元方法然后让他来调用。需要在这些方法中告诉他如何进行响应。有两种方式:
- 使用原生的response
- 使用SpringMVC的方式
1.0 项目配置
在web.xml中配置DispatcherServelet
<!--配置SpringMVC的servlet-->
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contectConfigLoaction</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置编码过滤器-->
<filter>
<filter-name>code</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>code</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在springMVC.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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置注解扫描-->
<context:component-scan base-package="com.bjsxt.controller"></context:component-scan>
<!-- 配置注解解析器-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置静态资源放行-->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
</beans>
1.1 使用response对象
springMVC02/01-springmvc-resp/src/com/bjsxt/controller/MyControllerResp.java
@Controller
public class MyControllerResp {
/* 使用response对象完成响应
* 1. 将单元方法返回值类型设置为void
* 使用响应对象直接响应,不再通过DispathcerServlet。既然已经响应则不再需要给DispatcherServlet返回值
* 2. 在单元方法上声明HttpServletResponse,来接收此次请求的response对象
* 3. 在单元方法中直接使用response对象完成响应
* 直接响应
* 请求转发
* 重定向
* */
@RequestMapping("resp")
public void demoResp(String uname, Integer age, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
// 处理请求
System.out.println("MyControllerResp.demoResp:使用原生的response方法完成响应:"+uname+":"+age);
// 响应结果
response.setContentType("text/html;charset=utf-8");
// 直接响应
// response.getWriter().write("直接响应");
// 请求转发
//request.getRequestDispatcher("./index.jsp").forward(request, response);
// 重定向
response.sendRedirect(request.getContextPath() + "/redirect.jsp");
}
}
1.2使用forward关键字完成响应
作用:实现请求转发
使用:通过单元方法的返回值来告诉DispatcherServlet请求转发指定的资源
代码示例:
1.请求转发jsp资源
/*
* 使用forward关键字完成请求转发
* 使用:通过单元方法的返回值,告诉DispatcherServlet要请求转发的资源
* 格式:
* return "forward:/jsp资源路径";
* 注意:
* 第一个/表示项目根目录
* */
@RequestMapping("fowardJsp")
public String demoForwardJsp(String uname, Integer age) {
// 处理请求
System.out.println("MyControllerResp.demoForwardJsp:forward请求转发jsp:" + uname + ":" + age);
// 响应结果
return "forward:/forward.jsp";
}
2.请求转发其他的单元方法
// 接收请求的方法
@RequestMapping("forwardMethod")
public String demoForwardMethod(String uname, Integer age) {
// 处理请求
System.out.println("MyControllerResp.demoForwardJsp:forward请求转发到单元方法:" + uname + ":" + age);
// 响应结果
return "forward:/testMethod";
}
// 接收转发的方法
@RequestMapping("testMethod")
public String testMethod(String uname, Integer age) {
// 处理请求
System.out.println("MyControllerResp.testMethod:forward被转发到的单元方法" + uname + ":" + age);
// 响应结果
return "aa";
}
1.3使用redirect关键字完成响应
1.使用redirect重定向到某个资源
@RequestMapping("redirectJsp")
public String demoRedirectJsp(String uname, Integer age) {
// 处理请求
System.out.println("MyControllerResp.demoRedirectJsp:重定向到jsp资源:"+uname + ":"+age);
// 响应结果
return "redirect:/redirect.jsp";
}
2.重定向到单元方法
@RequestMapping("redirectMethod")
public String demoRedirectMethod(String uname, Integer age) {
// 处理请求
System.out.println("MyControllerResp.demoRedirectMethod:重定向到单元方法:"+uname + ":"+age);
// 响应结果
return "redirect:/testMethod";
}
@RequestMapping("testMethod")
public String testMethod(String uname, Integer age) {
// 处理请求
System.out.println("MyControllerResp.testMethod:forward被转发到的单元方法" + uname + ":" + age);
// 响应结果
return "aa";
}
但是重定向是发送两次,所以testMethod显示的uname和age一定是null
第二节SSM整合登录案例
- 搭建SSM开发环境
- 创建用户表
- 实现登录功能
2.0 搭建SSM开发环境
- 导入jar包
- 创建controller、pojo、mapper和service
- 配置SS容器的applicationtext.xml和springmvc.xml
spring容器的配置文件applicationcontext.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
default-autowire="byName"
>
<!--属性文件扫描-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!-- 配置注解扫描-->
<context:component-scan base-package="com.bjsxt.service.impl"></context:component-scan>
<!-- 配置数据源bean-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${mysql.driver}"></property>
<property name="url" value="${mysql.url}"></property>
<property name="username" value="${mysql.username}"></property>
<property name="password" value="${mysql.password}"></property>
</bean>
<!-- 配置工厂bean -->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--property name="dataSource" ref="dataSource"></property> 因为配置了自动注入,即可不用再写这句话-->
</bean>
<!-- 配置mapper扫描bean-->
<bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="factory"></property>
<property name="basePackage" value="com.bjsxt.mapper"></property>
</bean>
<!-- 配置事务管理bean-->
<bean id = "transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 本来需要的,但因为搞了spring的自动注入则不再需要了-->
</bean>
<!--配置事务管理方法-->
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="sel*" read-only="true"/>
<tx:method name="ins*"/>
<tx:method name="up*"/>
<tx:method name="del*"/>
</tx:attributes>
</tx:advice>
<!--配置事务管理切面-->
<aop:config>
<aop:pointcut id="mp" expression="execution(* com.bjsxt.service.impl.*.*(..))"/>
<aop:advisor advice-ref="advice" pointcut-ref="mp"></aop:advisor>
</aop:config>
</beans>
springMVC的配置文件springmvc.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: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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置注解扫描的路径-->
<context:component-scan base-package="com.bjsxt.controller"></context:component-scan>
<!-- 注解解析器-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置静态资源放行-->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
</beans>
- 配置web.xml(DispatcherServlet、Code)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 配置spring容器的配置文件路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationcontext.xml</param-value>
</context-param>
<!-- 配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置DispactherServelt-->
<!--配置SpringMVC的servlet-->
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置编码过滤器-->
<filter>
<filter-name>code</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>
<!-- 设置作用范围-->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>code</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- 配置日志和数据库必需的log4j.properties和db.properties
日志配置文件log4j.properties:
log4j.rootCategory=info
log4j.logger.com.bjsxt.mapper=debug, CONSOLE,LOGFILE
log4j.logger.com.bjsxt.advice=debug, CONSOLE,LOGFILE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %c-%d-%m%n
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:/axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %c-%d-%m%n
数据库配置文件db.properties:
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/bjsxt
mysql.username=root
mysql.password=root
2.1功能的实现
前端代码:
<h3>ssm:整合案例之登录</h3>
<hr>
<form action="userLogin">
用户名:<input type="text" name="uname" value=""><br>
密码:<input type="password" name="pwd" value=""><br>
<input type="submit" value="登录">
</form>
controller代码:
springMVC容器是spring容器的子对象,controlloer在springMVC容器中,可以直接拿到被spring容器扫描创建的userServiceImpl对象。
springMVC02/02-ssm-login/src/com/bjsxt/controller/UserController.java
@Controller
public class UserController {
@Autowired // 这样就不需要写set、get方法了
private UserService userService;
@RequestMapping("userLogin")
public String userLogin(String uname, String pwd) {
User user = userService.selUserInfoService(uname, pwd);
if(user != null) {
return "redirect:/main.jsp";
}
else {
return "redirect:/login.jsp";
}
}
}
springMVC02/02-ssm-login/src/com/bjsxt/service/UserService.java
public interface UserService {
// 必须加sel,因为配置了事务
User selUserInfoService(String username, String password);
}
springMVC02/02-ssm-login/src/com/bjsxt/service/impl/UserServiceImpl.java
@Service //相当于把它弄成bean了
public class UserServiceImpl implements UserService {
// 声明mappper属性
@Autowired
private UserMapper userMapper;
// 登录业务方法
@Override
public User selUserInfoService(String username, String password) {
return userMapper.userLoginMapper(username, password);
}
}
springMVC02/02-ssm-login/src/com/bjsxt/mapper/UserMapper.java:
public interface UserMapper {
@Select("select * from t_user where uname=#{uname} and pwd=#{pwd}")
User userLoginMapper(@Param("uname")String uname,@Param("pwd") String pwd);
}
第三节 使用SpringMVC作用域对象完成数据的流转
3.1 作用域对象复习
- PageContext对象
- 当前jsp页面有效
- request对象
- 作用域范围:一次请求内
- 作用:解决了一次请求内的资源共享的问题
- session对象
- 作用域范围:一次会话内有效
- 说明:只要我们的浏览器不关闭(sessionID不失效),并且后台的session不失效,在任意请求中都可以获取到同一个session对象。第几次请求都无所谓,只看sessionID。而request对象只作用于一次
- 作用:解决了一个用户不同请求的数据共享问题
- application(ServletContext)对象
- 整个项目内
- 作用:解决了不同用户资源共享的问题,比如当前在线人数
- 特点:一个项目只有一个,在服务器启动的时候即完成初始化创建,无论如何获取都是一个项目
3.2 SpringMVC中使用作用域对象流转数据
tips:设置spring模板
file->settings->File and Code Templates
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置注解扫描的路径-->
<context:component-scan base-package="com.bjsxt.controller"></context:component-scan>
<!-- 注解解析器-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置静态资源放行-->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
</beans>
3.2.1. 使用request对象作为请求转发数据流转的载体
springMVC02/03-ssm-data/src/com/bjsxt/controller/MyController.java:
@Controller
public class MyController {
// 声明单元方法,使用request对象作为数据流转的载体
@RequestMapping("dataReq")
public String demoReq(HttpServletRequest request) {
// 处理请求
System.out.println("MyController.demoReq:使用request对象作为数据流转的载体");
// 响应结果
request.setAttribute("str", "我是request对象");
return "forward:/req.jsp";
}
}
随便弄一个前端:
<body>
${requestScope.str}
</body>
3.2.2. 使用session对象作用一个对象数据流转的载体
request作用于同一个请求,所以只能是forward,而session作用于同一个用户的不同请求,所以是redirect。
forward:将某个请求转发出去,这个请求还是这个请求
redirect:将这些参数重定向给某个,是不同的、两个请求
// 声明单元方法,使用session对象作为数据流转的载体
@RequestMapping("demoSession")
public String demoSession(HttpSession httpSession) {
// 处理请求
System.out.println("MyController.demoSession:使用session对象作为数据流转的载体");
// 响应结果
httpSession.setAttribute("str", "我是Session对象");
return "redirect:/session.jsp";
}
前端也很简单:
<body>
${sessionScope.str}
</body>
3.2.3. 使用application对象作为整个项目数据流转的载体
注意哦,ServletContext对象没有默认的无参构造器,所以该单元方法的形参,不是能ServletContext类型的
// 声明单元方法:使用applicationContext对象作为数据流转的载体
@RequestMapping("dataApplication")
public String demoApplication(HttpServletRequest request) {
System.out.println("MyController.demoApplication:使用application对象作为数据流转的载体");
ServletContext servletContext = request.getServletContext();
servletContext.setAttribute("str", "我是application对象");
return "redirect:/application.jsp";
}
前端代码也很简单:
<body>
${applicationScope.str}
</body>
3.3 SpringMVC的Model对象的使用
作用:作为数据流转的载体,SpringMVC官方提供的一个对象。
使用:在单元方法上声明Model形参即可
注意:Model是由DispatcherServlet创建并作为实参传递给单元方法使用
特点:
代码示例:
1.请求转发中使用model对象作为数据流转的载体
@RequestMapping("dataModel")
public String demoModel(Model model) {
System.out.println("MyController.demoModel:请求转发中使用model对象作为数据流转的载体");
model.addAttribute("str", "我是model对象--请求转发");
return "forward:/model.jsp";
}
前端中直接使用request就行了。请求转发中,model对象中存储的数据相当于存储到了request对象中。我们在jsp中直接按照request对象作用域取值的方式来获取即可。
<body>
${requestScope.str}
</body>
2.重定向中使用model对象作为数据流转的载体
redirect是两个不同的请求,所以如果重定向中使用model对象作为数据流转的载体来处理,会这样:
http://localhost:8080/mvc_data/model.jsp?str=我是model对象--请求转发
// 声明单元方法:请求转发中使用model对象作为数据流转的载体
@RequestMapping("dataModel2")
public String demoModel2(Model model) {
System.out.println("MyController.demoModel2:重定向中使用model对象作为数据流转的载体");
model.addAttribute("str", "我是model对象--请求转发");
return "redirect:/model.jsp";
}
前端代码中可以这样拿到参数:
<body>
${requestScope.str}---${param.str}
</body>
第四节 自定义视图解析器
写好的单元方法需要根据返回的String进行解析,这里是SpringMVC帮你解析的,帮你解析的这个对象就叫视图解析器,SpringMVC中DispatcherServlet来调用它。你可以来自定义它。
tomcat只认servlet的实例化对象
4.1 SpringMVC的视图解析器
- InterlResourceView
- RedirectView
- ModelAndView
4.1.1 使用View接口的子类对象来完成请求转发
springmvc官方提供了一个view的接口,告诉开发人员DS底层会调用view接口的实例化对象中的逻辑方法来完成对应的请求转发和重定向。
- InternalResourceView:请求转发
@Controller
public class MyController {
// 声明单元方法:使用View接口的子类对象来完成请求转发或重定向
@RequestMapping("demoView")
public View demoView() {
// 处理请求
System.out.println("MyController.demoView:View接口实例化对象完成请求转发|重定向");
// 响应结果
// 请求转发
return new InternalResourceView("req.jsp");
}
}
2.RedirectView:重定向转发
@Controller
public class MyController {
// 声明单元方法:使用View接口的子类对象来完成请求转发或重定向
@RequestMapping("demoView")
public View demoView(HttpServletRequest httpServletRequest) {
// 处理请求
System.out.println("MyController.demoView:View接口实例化对象完成请求转发|重定向");
// 响应结果
return new RedirectView(httpServletRequest.getContextPath() + "/redirect.jsp");
}
}
4.1.2 使用ModelAndView解析视图,并实现数据流转
现在的问题是需要根据不同的方法来生成视图解析器,过于麻烦,希望只有一个然后根据参数。——使用ModelAndView。
@RequestMapping("md")
public ModelAndView demoModelAndView() {
// 处理请求
System.out.println("MyController.modelAndView:ModelAndView视图解析器");
// 响应结果
// 创建model&view对象
ModelAndView modelAndView = new ModelAndView();
// 请求转发
modelAndView.setViewName("forward:/mdReq.jsp");
return modelAndView;
}
同时还能作数据的流转:
@RequestMapping("md")
public ModelAndView demoModelAndView() {
// 处理请求
System.out.println("MyController.modelAndView:ModelAndView视图解析器");
// 响应结果
// 创建model&view对象
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("str", "我是model流转数据");
// 请求转发
//modelAndView.setViewName("forward:/mdReq.jsp");
// 重定向
modelAndView.setViewName("redirect:/mdRedirect.jsp");
return modelAndView;
}
前端界面:
<body>
我是model&view重定向的页面
<hr>
${param.str}
</body>
SpringMVC再升级:希望连model&view都不要实例化,只要转发一堆字符串过去就行(资源路径、响应方式)。希望由springMVC直接创建model&view
我们一般使用的方法:
@RequestMapping("string")
public String demoString() {
System.out.println("MyController.demoString:近期一直在用的");
return "redirect:/redirect.jsp";
}
虽然单元方法返回的是字符串,但DispatcherServlet并不是直接使用字符串数据而是仍然调用model&view视图解析器完成请求转发或重定向
4.2 SpringMVC自定义视图解析器
目前在springmvc中虽然是直接返回字符串,但来表明请求转发或重定向的数据,但其实DS底层仍然使用的是model&view视图解析器。
model&view会将字符串拆分之后,来完成资源的跳转,比如"forward:/index.jsp,虽然强大,很满足不了生产环境中奇奇怪怪的特殊需求,是存在局限的。
比如文件的路径很有,a/b/c,每个都需要写一大堆,而且如果某一级路径一边,直接GG。但springmvc提供了一些向外的参数,可以由你来配置,从而相当于自定义视图解析器。
实现:InternalResourceViewResolver
概念:因为InternalResourceViewResolver可以让我们通过配置文件来设置一些常量参数,所以将该视图解析器称为自定义视图解析器。
使用:在springmvc.xml进行配置
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
比如在web/目录下创建/a/b/c/c.jsp,如果是正常使用,后端代码应该这么写:
@RequestMapping("mv")
public String demoMV() {
// 测试使用默认的model&view视图解析器
System.out.println("MyControllerView.demoMV:测试使用默认的model&view视图解析器");
return "forward:/a/b/c/c.jsp";
}
如果使用了自定义解析器,那么应该:
@RequestMapping("myView")
public String demoInternalResourceViewResolver() {
System.out.println("MyControllerView.demoInternalResourceViewResolver:自定义视图解析器");
return "c";
}
而不能写成:
@RequestMapping("myView")
public String demoInternalResourceViewResolver() {
System.out.println("MyControllerView.demoInternalResourceViewResolver:自定义视图解析器");
return "forward:/c"; // 这样的话它会去找名为“c”的单元方法
}
注意:只要带了关键字和冒号,DS就会使用model&view,而如果没有才会使用自定义的视图解析器。如果是redirect,默认使用默认的model&view解析器。
第五节 自定义视图解析器的使用
5.1 目前项目资源的声明位置和访问中存在的问题及解决方案
web/目录下有很多资源,如果用户知道URL地址,是可以直接访问到的,极不安全。相当于知道知道你们家地址,就能进去,非常不安全。想要控制一下权限。
WEB-INF/这个目录就像一个密室,只有经过tomcat转发的请求才会被允许,直接访问是会被拒绝的。
@Controller
public class MyController {
// 声明单元方法:检查请求,是否给密室中的资源
@RequestMapping("secret")
public String getJsp() {
// 处理请求
System.out.println("MyController.getJsp:检查请求是否合理");
// 响应请求
return "forward:/WEB-INF/jsp/cc.jsp";
}
}
而如果直接访问:http://localhost:8080/view-use/WEB-INF/jsp/cc.jsp 会被拒绝
5.2 使用自定义视图解析器优化资源跳转路径
还可以用自定义视图解析器来优化,保密文件的跳转路径
@RequestMapping("secret")
public String getJsp() {
// 处理请求
System.out.println("MyController.getJsp:检查请求是否合理");
// 响应请求
return "cc";
}
自定义视图解析器配置:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
5.3 使用Restful声明单元公共方法请求转发下的WEB-INF下的资源
麻烦:资源很多,总不能每一个都写一个方法(要转发的资源是根据单元方法返回的字符串确定的)
解决方案:声明一个公共的单元方法,不参与请求逻辑,而只是负责转发请求
@RequestMapping("{url}") //模糊匹配
public String getJsp3(@PathVariable String url) {
System.out.println("MyController.getJsp3:公共单元方法,请求转发web-inf下的资源");
return url;
}
别忘了这也经历过springmvc的配置:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
第六节 springmvc上传
6.3 前台代码的实现
1.在页面中弄一个标签,
2.上传成功后响应结果在当前页面显示,使用ajax请求来完成资源的发送
3. 请求数据:上传的数据文件本身&用户名、id
4. 数据的格式:传统的请求中,是以键值对的形式发送数据。在上传请求中,用ajax发送一个二进制流的方式发送给服务器。
5. ajax以二进制形式将数据发送给服务
- 创建formData表单数据,将请求数据存储到该对象中发送
- 将processData属性设置为false,告诉浏览器发送对象请求数据
- 将contentType属性设置为false,设置请求数据的类型为二进制数据
- 正常发送ajax即可
6.上传成功后,后台服务器应该响应什么结果给浏览器,并且浏览器该如何处理。响应一个json对象给浏览器。示例格式如下:
{
status:true,
msg: 服务器繁忙,
url:上传成功
首先创建表单:
<%--创建注册页面--%>
<h3 align="center">欢迎注册502班级系统</h3>
<hr>
<%--创建注册表单--%>
<div style="width:600px;margin: auto;">
<form action="userReg" method="post">
<table cellpadding="10px" style="margin: auto;margin-top:20px;">
<tr>
<td>用户名:</td>
<td>
<input type="text" name="uname" value=""><br>
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input type="password" name="pwd" value=""><br>
</td>
</tr>
<tr>
<td>头像:</td>
<td>
<input type="file" id="file" value="点击选择头像"> <a id="btnUpload" href="javascript:void(0)">点击上传</a>
<input type="hidden" name="img" id="img" value=""><%--隐藏标签记录上传成功的头像的url地址--%>
<img src="" style="display: none" id="myImg" width="100px">
</td>
</tr>
<tr>
<td colspan="2" >
<input type="submit" value="完成注册">
</td>
</tr>
</table>
</form>
</div>
接着引入jquery,并使用ajax请求发送数据和url信息,
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="<%=basePath %>"/>
<title>Title</title>
<%--引入jquery文件--%>
<script type="text/javascript" src="js/j.js"></script>
<%--声明js代码域--%>
<script type="text/javascript">
/****************资源上传功能实现**********************************/
$(function () {
//给上传按钮增加单击事件
$("#btnUpload").click(function () {
//获取要上传的文件资源
var file=$("#file")[0].files[0];
//创建FormData对象存储要上传的资源
var formData=new FormData();
formData.append("photo",file);
//发起ajax请求完成资源上传
$.ajax({
type:"post",//使用post类型的请求
data:formData,//请求数据
url:"regUpload",//请求地址
processData:false,
contentType:false,
success:function (data) {//回调函数
//将响应数据转换为json对象
eval("var obj="+data);
//判断
if(obj.status==true){
alert("上传成功");
//将用户的头像的url地址信息记录下来
$("#img").val(obj.url);
//在页面中显示上传的头像
$("#myImg").attr("src","upload/"+obj.url).css("display","");
}else{
alert(obj.msg);
}
}
})
})
})
</script>
</head>
<body>
6.5 后台代码的实现
@Controller
public class RegController {
// 声明业务层属性
@Autowired
private RegService regService;
// 声明单元方法,完成用户注册
@RequestMapping("userReg")
public String userReg(User user) { // 为什么能直接接一个User?
int i = regService.insUserInfoService(user);
return "redirect:/login.jsp";
}
// 声明单元方法
@RequestMapping("regUpload")
public void regUpload(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, MultipartFile photo) throws IOException {
// 1. 确定文件存储路径
// 动态获取项目存储路径
// 项目最终都是会保存在:out\artifacts\06_smm_upload_war_exploded下的
// 使用servletContext对象动态获取项目根目录下的upload文件夹的路径作为资源存储路径。
String path = httpServletRequest.getServletContext().getRealPath("/upload");
System.out.println(path);
// 2. 确定文件存储的名字
// 获取文件的原始名 abc.jpg
String oldName = photo.getOriginalFilename();
// 获取文件存储的后缀名
String suffix = oldName.substring(oldName.lastIndexOf("."));
// 创建文件的新名字
String newName = UUID.randomUUID()+""+suffix;
// 3. 完成存储
// 创建file对象存储资源路径
File file = new File(path);
if(!file.exists()) {
file.mkdirs(); // 创建存储路径
}
// 输出存储
photo.transferTo(new File(file, newName));
// 4. 响应结果
// 创建UploadResult对象存储响应数据
UploadResult uploadResult = new UploadResult(true, "", newName);
// 将uploadresult对象转成json格式
String jsonStr = new Gson().toJson(uploadResult);
// 直接响应
httpServletResponse.getWriter().write(jsonStr);
}
}
其中的uploadRequest是pojo中的一个类:
public class UploadResult {
private Boolean status;
private String msg;
private String url;
6.6 注册功能的实现
前端代码增加了两个标签,一个用来保存图片的url,一个用来显示图片。
<td>
<input type="file" id="file" value="点击选择头像"> <a id="btnUpload" href="javascript:void(0)">点击上传</a>
<input type="hidden" name="img" id="img" value=""><%--隐藏标签记录上传成功的头像的url地址--%>
<img src="" style="display: none" id="myImg" width="100px">
</td>
如果上传成功了,则给url赋值并显示界面:
if(obj.status==true){
alert("上传成功");
//将用户的头像的url地址信息记录下来
$("#img").val(obj.url);
//在页面中显示上传的头像
$("#myImg").attr("src","upload/"+obj.url).css("display","");
}else{
alert(obj.msg);
}
接下来仍然是CSM架构下的类的创建:
RegController:
@Controller
public class RegController {
// 声明业务层属性
@Autowired
private RegService regService;
// 声明单元方法,完成用户注册
@RequestMapping("userReg")
public String userReg(User user) { // 为什么能直接接一个User?
int i = regService.insUserInfoService(user);
return "redirect:/login.jsp";
}
RegService:
public interface RegService {
// 用户注册
int insUserInfoService(User user);
}
RegService的实现类:
package com.bjsxt.service.impl;
import com.bjsxt.mapper.RegMapper;
import com.bjsxt.pojo.User;
import com.bjsxt.service.RegService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service //
public class RegServiceImpl implements RegService {
@Autowired
private RegMapper regMapper;
@Override
public int insUserInfoService(User user) {
return regMapper.insUserInfoMapper(user);
}
}
以及RegMapper类:
public interface RegMapper {
// 用户注册
@Insert("insert into t_user values(default, #{uname}, #{pwd}, #{img}")
int insUserInfoMapper(User user);
}
第七节 SpringMVC下载
7.2 下载的请求数据
前端代码:
<body>
<h3>SpringMVC的下载</h3>
<hr>
<a href="downFile?filename=testPic.png">点击下载</a>
</body>
后台代码:
@Controller
public class DownController {
// 声明单元方法:处理下载请求
@RequestMapping("downFile")
public void downFile(String filename, HttpServletResponse httpServletResponse, HttpServletRequest httpServletRequest) throws IOException {
// 1.获取要下载的资源的流对象
// 设置响应头,告诉浏览器下载的资源需要存储到客户端的硬盘中,而非解析打开
httpServletResponse.setHeader("Content-Disposition", "attachment;filename"+filename);
// 获取资源的绝对路径
String path = httpServletRequest.getServletContext().getRealPath("/upload");
System.out.println(path);
// 获取文件的二进制数据
byte[] bytes = FileUtils.readFileToByteArray(new File(path, filename));
// 2. 响应浏览器
// 获取输出流对象
ServletOutputStream servletOutputStream = httpServletResponse.getOutputStream();
// 响应资源
servletOutputStream.write(bytes);
}
}
这里出现的bug是,我在web.iml连spring的配置都没配上,正确的SSM框架的项目的web.xml应该是:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 配置spring容器的配置文件路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationcontext.xml</param-value>
</context-param>
<!-- 配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置SpringMVC的servlet-->
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置编码过滤器-->
<filter>
<filter-name>code</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>
<!-- 设置作用范围-->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>code</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>