一起學習SSM框架之SpringMVC(五)

ozl520發表於2020-10-26

上傳

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執行流程

在這裡插入圖片描述

相關文章