北京尚学堂2020java_SpringMVC第二天

第一节 SpringMVC的响应

使用了SpringMVC之后,servlet只有一个,那就是DispatcherServlet。但它又不是我们声明的,需要在外部声明单元方法然后让他来调用。需要在这些方法中告诉他如何进行响应。有两种方式:

  1. 使用原生的response
  2. 使用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整合登录案例

  1. 搭建SSM开发环境
  2. 创建用户表
  3. 实现登录功能

2.0 搭建SSM开发环境

  1. 导入jar包
  2. 创建controller、pojo、mapper和service
  3. 配置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>
  1. 配置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>
  1. 配置日志和数据库必需的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 作用域对象复习

  1. PageContext对象
  2. 当前jsp页面有效
  3. request对象
  4. 作用域范围:一次请求内
  5. 作用:解决了一次请求内的资源共享的问题
  6. session对象
  7. 作用域范围:一次会话内有效
  8. 说明:只要我们的浏览器不关闭(sessionID不失效),并且后台的session不失效,在任意请求中都可以获取到同一个session对象。第几次请求都无所谓,只看sessionID。而request对象只作用于一次
  9. 作用:解决了一个用户不同请求的数据共享问题
  10. application(ServletContext)对象
  11. 整个项目内
  12. 作用:解决了不同用户资源共享的问题,比如当前在线人数
  13. 特点:一个项目只有一个,在服务器启动的时候即完成初始化创建,无论如何获取都是一个项目

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接口的实例化对象中的逻辑方法来完成对应的请求转发和重定向。

  1. 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以二进制形式将数据发送给服务

  1. 创建formData表单数据,将请求数据存储到该对象中发送
  2. 将processData属性设置为false,告诉浏览器发送对象请求数据
  3. 将contentType属性设置为false,设置请求数据的类型为二进制数据
  4. 正常发送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="点击选择头像">&nbsp;<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="点击选择头像">&nbsp;<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>
posted @ 2022-02-04 17:32  明卿册  阅读(30)  评论(0编辑  收藏  举报