一起学习SSM框架之SpringMVC(五)

上传

1.导入依赖

 <!--io-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <!--文件上传-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

2.表单

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/upload/test1" method="post" enctype="multipart/form-data">
        file:<input type="file" name="source"><br>
        <input type="submit" value="上传">
    </form>
</body>
</html>

3.上传解析器

上传解析器id必须是"multipartResolve"

  <!--上传解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--最大可上传文件大小 byte 超出后会抛出MaxUploadSizeExceededException异常,可以在异常解析器捕获-->
        <!--<property name="maxUploadSize" value="1048576"></property>环境不同容易出现问题,所以不建议,建议使用拦截器-->
    </bean>

4.拦截器

拦截超过上传文件最大值,并抛出MaxUploadSizeExceededException异常
MyFileUploadInterceptor


public class MyFileUploadInterceptor implements HandlerInterceptor {
    private Long maxFileuploadSize;

    public Long getMaxFileuploadSize() {
        return maxFileuploadSize;
    }

    public void setMaxFileuploadSize(Long maxFileuploadSize) {
        this.maxFileuploadSize = maxFileuploadSize;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断上传文件大小
        ServletRequestContext servletRequestContext = new ServletRequestContext(request);
        //文件大小
        long l = servletRequestContext.contentLength();
        if (l>maxFileuploadSize){
            throw new MaxUploadSizeExceededException(1048576);
        }
        return true;
    }
}

mvc.xml
ioc注入

  <mvc:interceptor>
            <mvc:mapping path="/upload/*"/>
            <bean class="cn.ozl.interceptor.MyFileUploadInterceptor">
                <property name="maxFileuploadSize" value="1048576"></property>
            </bean>
        </mvc:interceptor>

5.异常解析器

捕获异常,并跳转异常页面
MyExceptionResolver

//异常解析器
//任何一个handler中抛出异常都会捕获
public class MyExceptionResolver implements HandlerExceptionResolver {

    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        if (e instanceof MyException1){
            modelAndView.setViewName("redirect:/error1.jsp");
        }else if (e instanceof MyException2){
            modelAndView.setViewName("redirect:/error2.jsp");
        }else if(e instanceof MaxUploadSizeExceededException){
            modelAndView.setViewName("redirect:/uploadError.jsp");
        }
        return modelAndView;
    }
}

mvc.xml


    <!--异常解析器-->
    <bean class="cn.ozl.resolver.MyExceptionResolver"></bean>

6.Handler

获取上传文件,用uuid唯一id命名文件,并保存

@Controller
@RequestMapping("/upload")
public class UploadController {
    @RequestMapping("/test1")
    public String test1(MultipartFile source, HttpSession session) throws IOException {
        System.out.println("test1");
        //获取上传文件的原始名称
        String originalFilename = source.getOriginalFilename();
        //生成一个唯一的文件名
        String s = UUID.randomUUID().toString();
        //获取文件后缀扩展名
        String extension = FilenameUtils.getExtension(originalFilename);
        //拼接完整唯一的文件名
        String filename=s+"."+extension;
        //获取上传文件的类型
        String contentType = source.getContentType();
        System.out.println(originalFilename);
        System.out.println(contentType);

        //保存文件
//        source.transferTo(new File("f://adc.js"));
        String realPath = session.getServletContext().getRealPath("/upload");
        System.out.println("realPath:"+realPath);
        source.transferTo(new File(realPath+"\\"+filename));
        return "index";
    }
}

下载

1.超链接

显示一个下载的超链接

download.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/download/test1?name=jquery-2.1.1.js">下载</a>
</body>
</html>

2.Handler

下载操作

@Controller
@RequestMapping("/download")
public class DownloadController {
    @RequestMapping("/test1")
    public void test1(String name, HttpSession session, HttpServletResponse response) throws IOException {
        String realPath = session.getServletContext().getRealPath("/upload");
        String filepath = realPath + "\\" + name;
        //设置响应头,告知浏览器,要以附件形式保存内容 filename=浏览器显示的下载文件
        response.setHeader("content-disposition","attachment;filename="+name);
        //响应
        IOUtils.copy(new FileInputStream(filepath),response.getOutputStream());

    }
}

验证码Kaptcha

为了防止暴力破解

1.导入依赖

   <!--Kaptcha验证-->
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

2.声明验证码组件

web.xml

 <!--kaptcha样式配置-->
    <servlet>
        <servlet-name>cap</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
        <!-- 定义验证码样式 -->
        <!-- 是否有边框 -->
        <init-param>
            <param-name>kaptcha.border</param-name>
            <!-- 没有边框 no -->
            <param-value>no</param-value>
        </init-param>

        <!-- 使用哪些字符生成验证码 -->
        <init-param>
            <param-name>kaptcha.textProducer.char.string</param-name>
            <param-value>ACDEFHIJKLMNOPQRSTUVWXYZ123456790abcdefghijklmnopqrstuvwxyz</param-value>
        </init-param>
  
        <!-- 验证码字符个数 -->
        <init-param>
            <param-name>kaptcha.textproducer.char.length</param-name>
            <param-value>4</param-value>
        </init-param>
        <init-param>
            <param-name>kaptcha.background.clear.to</param-name>
            <param-value>211,229,237</param-value>
        </init-param>
        <!--session.setAttribute("captcha","验证码")-->
        <init-param>
            <param-name>kaptcha.session.key</param-name>
            <param-value>captcha</param-value>
        </init-param>
        
        <init-param>
            <param-name>kaptcha.session.date</param-name>
            <param-value></param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>cap</servlet-name>
        <url-pattern>/captcha</url-pattern>
    </servlet-mapping>

3.页面

captcha.jsp
表单提交验证码,实现点击刷新验证码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/captcha/test1" >
        <img  id="cap" src="${pageContext.request.contextPath}/captcha" style="width: 100px" onclick="refresh()">
        <input type="text" name="captcha">
        <br>
        <input type="submit" value="提交" onclick="refresh()">
    </form>
    <script>
        function refresh1(){
            var img=document.getElementById("cap")
            img.src="${pageContext.request.contextPath}/captcha?"+new Date().getTime()
        }


    </script>
</body>
</html>

4.Handler

CaptchaController
进行验证码校验

@Controller
@RequestMapping("/captcha")
public class CaptchaController {
    @RequestMapping("/test1")
    public String test1(String captcha, HttpSession session){
        String captcha1 =(String)session.getAttribute("captcha");
        if (captcha1.equals(captcha)){
            return "index";
        }
        return "error1";
    }
}

REST

1.开发风格

是一种开发风格,遵此风格的开发软件,符合REST风格,则RESTFUL
两个核心要求:
1.每个资源都有唯一的标识(url)
2.不同的行为,使用对应的http-method

2.优点

1.看url就知道要什么
2.看http-method就知道干什么

3.使用

3.1定义Rest风格的Controller

MyRestController

/*
* 查询: 所有用户
*       查询id=xx 的某一个用户
* 删除: id=xx 的某一个用户
* 增加: 所有用户中增加一个
* 修改: 所有用户中修改一个
*
* 资源: 所有用户        /users
*       id=xx 某个用户   /users/{id}
* */
@RestController
public class MyRestController {
    @GetMapping("/users")
    public List<User> queryUsers(){
        System.out.println("查询所有的用户 get请求方式");
        User user = new User(1, "李四");
        User user1 = new User(2, "张三");
        return Arrays.asList(user,user1);
    }

    @GetMapping("/users/{id}")
    public User queryUser(@PathVariable Integer id){
        System.out.println("查询id="+id+"的用户 get请求方式");
        return new User(1, "李四");
    }

    @DeleteMapping("/users/{id}")
    public String deleteUser(@PathVariable Integer id){
        System.out.println("删除id="+id+"的用户 delete请求方式");
        return "ok";
    }
    @PostMapping("/users")
    public String saveUser(@RequestBody User user){
        System.out.println("保存用户 post请求方式"+user);
        return "ok";
    }
    @PutMapping("/users")
    public String updateUser(@RequestBody User user){
        System.out.println("修改用户 put请求方式"+user);
        return "ok";
    }
}

3.2Ajax请求

rest.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery-2.1.1.js"></script>
</head>
<body>
    <input type="button" value="查询所有用户" onclick="queryAll();">
    <input type="button" value="查询特定用户" onclick="queryOne();">
    <input type="button" value="删除特定用户" onclick="deleteOne();">
    <input type="button" value="修改特定用户" onclick="updateOne();">
    <input type="button" value="保存特定用户" onclick="saveOne();">
    <script>
        function queryAll(){
            $.ajax(
                {
                    url:"${pageContext.request.contextPath}/users",
                    type:"get",
                    success:function (ret){
                        console.log("查询所有:");
                        console.log(ret);
                    }
                }
            )
        }
        function queryOne(){
            $.ajax(
                {
                    url:"${pageContext.request.contextPath}/users/1",
                    type:"get",
                    success:function (ret){
                        console.log("查询特定用户:");
                        console.log(ret);
                    }
                }
            )
        }
        function deleteOne(){
            $.ajax(
                {
                    url:"${pageContext.request.contextPath}/users/1",
                    type:"delete",
                    success:function (ret){
                        console.log("删除特定用户:");
                        console.log(ret);
                    }
                }
            )
        }
        function updateOne(){
            var user={id:1,name:"李四"}
            var userJson=JSON.stringify(user)
            $.ajax(
                {
                    url:"${pageContext.request.contextPath}/users",
                    type:"put",
                    data:userJson,
                    contentType:"application/json",
                    success:function (ret){
                        console.log("修改特定用户:");
                        console.log(ret);
                    }
                }
            )
        }
        function saveOne(){
            var user={id:1,name:"张三"};
            var userJson=JSON.stringify(user);
            $.ajax(
                {
                    url:"${pageContext.request.contextPath}/users",
                    type:"post",
                    data:userJson,
                    contentType:"application/json",
                    success:function (ret){
                        console.log("修改特定用户:");
                        console.log(ret);
                    }
                }
            )
        }
    </script>
</body>
</html>

跨域请求

1.域

域:协议+IP+端口
http://localhost:8989

2.Ajax跨域问题

1.Ajax发送请求时,不允许跨域,以防用户信息泄露
2.当Ajax跨域请求时,响应会被浏览器拦截(同源策略),并报错,即浏览器默认不允许,ajax跨域得到响应内容
3.相互信任的域之间如果需要ajax访问,(比如前后端分离项目中,前端项目和后端项目之间),则需要额外的设置才可正常请求

3.解决方案

允许其他域访问

在被访问的Controller类上,添加注解

@CrossOrign("http://localhost:8080")//允许此域发请求访问

携带对方的cookie,使得session可用
在访问方,ajax中添加属性:withCredentials:true

 xhrFields:{
                    //跨域携带cookie
                    withCredentials:true
                },

SpringMVC执行流程

在这里插入图片描述

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页