Part I: https://hackmd.io/@aaronlife/2023-java-1-1
Part II: https://hackmd.io/@aaronlife/2023-java-1
https://nodejs.org/dist/v18.17.0/node-v18.17.0-x64.msi
https://nodejs.org/en/blog/release/v18.17.0
Yarn是一個新的套件管理器,可以用來替代npm或其他套件管理器,相容於npm套件管理檔案(package.json)。與原本的npm工作流程相同,但是執行速度更快,更安全,更可靠,用Yarn來安裝套件比起npm更來的快。
確認安裝是否成功:
$ node --version
v18.17.0
如果有出現版本號碼,但表安裝成功
$ corepack enable
$ corepack prepare yarn@stable --activate
注意:
該指令需要系統管理員權限
Remove Yarn
$ corepack disable yarn
$ yarn create vite my-vue-app --template vue
$ yarn // 初始化專案
$ yarn dev // 啟動dev-server
# yarn build
$ yarn add vite
狀態管理套件,用來跨元件或是跨網頁分享狀態及資料。
$ yarn add pinia
vue-router用在SPA(Single Page Application)開發上,一般網站在換頁通常會透過URL來交給後端處理。而SPA方式可以減少讀取時間,目前許多前端框架(如: Vue.js, React.js)大多都採用SPA(單頁式應用)方式來開發,在切換畫面時仍然需要控制網址,讓SPA網頁可以根據網址做切換,所以才會有vue-router出現,讓前端在切換畫面時不需向後端發出請求
$ yarn add vue-router@4
注意:
Vue 3請安裝vue-router v4.0版本,v3.0是給Vue 2用的
<router-view></router-view>
// 引入vue-router
import {createRouter, createWebHistory} from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
import MyFirst from './components/MyFirst.vue'
import ShowMe from './components/ShowMe.vue'
import User from './pages/User.vue'
import MB from './pages/MyBootstrap.vue'
const routes = [
{
path: '/',
component: MB
},
{
path: '/helloworld',
component: HelloWorld
},
{
path: '/myfirst',
component: MyFirst
},
{
path: '/uch',
component: ShowMe
},
{
path: '/user',
component: User
},
];
// 建立VueRouter
const router = createRouter({
mode: 'history',
// 4. Provide the history implementation to use. We are using the hash history for simplicity here.
history: createWebHistory(),
routes, // short for `routes: routes`
});
export default {
router
}
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router' // 引入router.js
// 建立Vue app
const app = createApp(App);
// 將vue-router傳給vue app
app.use(router.router);
// mount Vue.js到網頁
app.mount('#app')
<script setup>
</script>
<template>
<router-view></router-view>
</template>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
<template>
<h1>My First</h1>
<div>name={{ $route.query.test }}</div>
<div>password={{ $route.query.password }}</div>
<div>role={{ $route.query.role }}</div>
</template>
<script>
export default {
name: "MyFirst",
props: ['count'] // 接收count變數
}
</script>
<style scoped>
h1 {
color: royalblue;
z-index: 9;
}
</style>
<script setup>
import { ref } from 'vue'
defineProps({
msg: String,
})
const count = ref(0)
</script>
<template>
<h1>Hello World</h1>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>
<template>
<img src="https://i0.wp.com/www.fotobeginner.com/wp-content/uploads/2015/04/lake-sunset-2021-08-26-18-27-36-utc-1.jpg" alt="uch"/>
</template>
<script>
export default {
name: "ShowMe",
}
</script>
<style scoped>
img {
z-index: 0 !important;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
box-sizing: border-box;
border: 0;
overflow: hidden;
object-fit: cover;
}
</style>
<template>
<ShowMe />
<MyFirst class="my-first"/>
<input type="button" value="Push Me" class="my-first" @click="onClick">
</template>
<script>
import ShowMe from '../components/ShowMe.vue';
import MyFirst from '../components/MyFirst.vue';
export default {
name: 'User',
components: {
ShowMe,
MyFirst,
},
methods: {
onClick() {
alert('Hello')
}
}
}
</script>
<style scoped>
.my-first {
position: relative;
}
</style>
<template>
<button type="button" class="btn btn-primary">Primary</button>
<button type="button" class="btn btn-secondary">Secondary</button>
<button type="button" class="btn btn-success">Success</button>
<button type="button" class="btn btn-danger">Danger</button>
<button type="button" class="btn btn-warning">Warning</button>
<button type="button" class="btn btn-info">Info</button>
<button type="button" class="btn btn-light">Light</button>
<button type="button" class="btn btn-dark">Dark</button>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Modal title</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
這是一個訊息框
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
<button type="button" class="btn btn-primary" id="liveToastBtn">Show live toast</button>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<img style="width: 32px" src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Instagram_icon.png/2048px-Instagram_icon.png" class="rounded me-2" alt="...">
<strong class="me-auto">Bootstrap</strong>
<small>11 mins ago</small>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
Hello, world! This is a toast message.
</div>
</div>
</div>
</template>
<script>
import * as bootstrap from 'bootstrap'
export default {
name: 'MyBootstrap',
mounted() {
const toastTrigger = document.getElementById('liveToastBtn')
const toastLiveExample = document.getElementById('liveToast')
if (toastTrigger) {
const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
toastTrigger.addEventListener('click', () => {
toastBootstrap.show()
})
}
},
methods: {
onClick() {
}
}
}
</script>
<style scoped></style>
@import 'bootstrap/dist/css/bootstrap.css';
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
$ yarn add bootstrap@5.3.0
如果上面安裝有問題,可以嘗試下面的方式:
$ yarn add @popperjs/core
$ yarn add bootstrap
import * as bootstrap from 'bootstrap'
<style>
@import 'bootstrap/dist/css/bootstrap.css';
</style>
@import "bootstrap/scss/bootstrap";
由於網頁是基於HTTP協定下的功能,而HTTP協定是無狀態協定(stateless),所以,需要跨網頁傳遞的資料(例如: 登入、使用者資訊、購買清單),就可以使用cookies、localStorage、session來儲存;cookies和localStorage是屬於前端的技術,而session屬於後端,使用前端技術來跨網頁傳遞資料好處是可以降低伺服器資源覆載,但缺點是較無安全性,而使用session的話雖然會增加伺服器的工作覆載,但是卻可以提高安全性。
下面介紹的使用方式是Servlet的標準功能,而非Spring的功能
步驟一: 在需要使用Session的API方法加上HttpSession
參數,例如:
@RequestMapping(value = "/login", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public LoginResponse Login(String username, String password, HttpSession session) {
LoginResponse loginResponse = checkAccount(username, password);
if(loginResponse.getCode() == 0)
session.setAttribute("loginStatus", username + ", " + password + "已登入");
else
session.removeAttribute("loginStatus");
return loginResponse;
}
然後可以再需要使用Session的API內也加上HttpSession
,例如:
@RequestMapping(value = "/movieimg", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public MovieimgResponse movies(HttpSession session) {
String loginStatus = (String)session.getAttribute("loginStatus");
System.out.println("get loginStatus: " + loginStatus);
if(loginStatus != null)
return getMovieimgList();
else
return new MovieimgResponse(9, "未登入", null);
}
server.servlet.session.timeout=1m
Filter又稱為過濾器,對API、靜態網頁、文件、圖片等等的請求進行攔截並檢查,可以用來實現權限控制、資源過濾等等的功能
使用Sprint Boot的註釋語法如下:
@WebFilter(urlPatterns = "/*", filterName = "myFilter")
public class MyFilter extends OncePerRequestFilter {
// 不需要進行過濾的網址
private static final Set<String> ALLOWED_PATHS = new HashSet<>(Arrays.asList("/login"));
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
System.out.println(request.getRequestURL());
System.out.println(request.getServletPath());
// 不需要過濾的網址直接跳過
if(ALLOWED_PATHS.contains(request.getServletPath())) {
filterChain.doFilter(request, response);
return;
}
// 從session取得登入狀態
String loginStatus = (String) request.getSession().getAttribute("loginStatus");
// 用來將物件轉成JSON字串
ObjectMapper objectMapper = new ObjectMapper();
if (loginStatus != null)
// 通過檢查,繼續進行下一個過濾器或API
filterChain.doFilter(request, response);
else {
// 直接回應前端
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("utf-8");
response.getWriter().println(objectMapper.writeValueAsString(new BaseResponse(9, "not login")));
}
}
}
@WebFilter
來建立FilterurlPatterns
設定要進行過濾的網址OncePerRequestFilter
filterChain.doFilter()
方法繼續進行下一步,否則會中斷原本應該要執行的API功能。注意:
filterName的第一個字母必須是小寫
main()
方法加上@ServletComponentScan
註釋因為@WebFilter
並不是Spring Boot的語法,不會自動抓到該過濾器,所以須加上讓Spring Boot可以掃描並抓到該過濾器。
@SpringBootApplication
@ServletComponentScan
public class MovieProjectApplication {
public static void main(String[] args) {
SpringApplication.run(MovieProjectApplication.class, args);
}
}
https://v3.router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations
新增
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.1.0</version>
</dependency>
瀏覽網址: http://localhost:8080/v3/api-docs
Swagger文件
瀏覽網址: http://localhost:8080/swagger-ui/index.html#/
Swagger UI
如果覺得Swagger UI網址太長,可以設定別名
springdoc.swagger-ui.path=/sw
@OpenAPIDefinition(info = @Info(title = "健行Java班API系統", version = "1.0.1"))
這個API要放到SpringBoot的Application類別內,例如:
@OpenAPIDefinition(info = @Info(title = "健行Java班API系統", version = "1.0.1"))
@SpringBootApplication
public class FinalprojectApplication {
public static void main(String[] args) {
SpringApplication.run(FinalprojectApplication.class, args);
}
}
@Tag(name = "登入")
@Operation(summary = "登入系統", description = "登入這個超級系統")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "API執行成功", content = {
@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = LoginResponse.class)))
}),
@ApiResponse(responseCode = "401", description = "沒有權限", content = {
@Content()
}),
@ApiResponse(responseCode = "500", description = "伺服器內部錯誤", content = {
@Content()
})
})
備註:
@Tag
和@Operation
和ApiResponses
都需要設定在API的方法上,例如:
@RequestMapping(value = "/login", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@Tag(name = "登入API")
@Operation(summary = "登入系統", description = "登入這個超級系統")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "API執行成功", content = {
@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = LoginResponse.class)))
}),
@ApiResponse(responseCode = "401", description = "沒有權限", content = {
@Content()
}),
@ApiResponse(responseCode = "999", description = "伺服器內部錯誤", content = {
@Content()
})
})
public LoginResponse Login(
@Parameter(description = "帳號名稱", example = "andy")
(defaultValue = "") String username,
@Parameter(description = "密碼", example = "1234") @RequestParam(defaultValue = "") String password) {
return checkAccount(username, password);
}
@RequestMapping(value = "/login", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public LoginResponse Login(
@Parameter(description = "帳號名稱", example = "andy") @RequestParam(defaultValue = "") String username,
@Parameter(description = "密碼", example = "1234") @RequestParam(defaultValue = "") String password) {
return checkAccount(username, password);
}
注意:
參數說命都是設定在方法內的參數列上
@Parameter(description = "平台分類", example = "[\"A\", \"B\"]") @RequestParam(defaultValue = "") ArrayList<String> platform,
此範例設定預設值為: ["A", "B"]
先在方法內加入:
@Parameter(description = "遊戲內容") GameEntity data
然後該物件內新@Schema
註記:
@Data
public class GameEntity {
@Schema(description = "遊戲ID")
int id;
@Schema(description = "遊戲名稱")
String name;
@Schema(description = "遊戲分類")
String category;
@Schema(description = "價格")
int price;
@Schema(description = "最新進貨日")
Date inchange;
@Schema(description = "最後進貨日")
Date outchange;
@Schema(description = "數量")
int quantity;
@Schema(description = "開發商")
String developer;
@Schema(description = "平台")
String platform;
}
springdoc.api-docs.enabled=false
springdoc.swagger-ui.enabled=false
@Value
@Data
@Component
@Autowired
https://github.com/ncu2023/FinalProject.git
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
target/
package com.uch.finalproject;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.yaml.snakeyaml.representer.BaseRepresenter;
import com.uch.finalproject.model.BaseResponse;
import com.uch.finalproject.model.LoginResponse;
@RestController
public class LoginController {
@RequestMapping(value = "/login", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public LoginResponse Login(String username, String password) {
return checkAccount(username, password);
}
// 判斷帳號是否存在
private LoginResponse checkAccount(String username, String password) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
// 註冊mySQL資料庫驅動程式
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 連線資料庫
conn = DriverManager.getConnection("jdbc:mysql://localhost/shopping?" +
"user=root&password=0000");
// 取得Statement物件
stmt = conn.createStatement();
// 查詢該帳號是否存在
rs = stmt.executeQuery("select count(*) as c from account where name='" + username + "'");
// 判斷帳號是否存在
rs.next(); // 跳到查詢結果的第一筆資料
int c = rs.getInt("c"); // 查詢到的資料筆數
// if(c == 0) {
// return new LoginResponse(2, "帳號不存在");
// } else {
// return new LoginResponse(0, "成功");
// }
// 帳號不存在,直接返回錯誤
if(c == 0) {
// 把資料庫相關資源釋放
rs.close();
stmt.close();
conn.close();
return new LoginResponse(2, "帳號不存在");
}
// 帳號存在,繼續判斷密碼
rs = stmt.executeQuery("select count(*) as c from account " +
"where name='" + username + "' and password='" + password + "';");
// 移動到第一筆資料
rs.next();
c = rs.getInt("c"); // 查詢到的資料筆數
// 把資料庫相關資源釋放
rs.close();
stmt.close();
conn.close();
// 密碼錯誤
if(c == 0) {
return new LoginResponse(3, "密碼錯誤");
}
return new LoginResponse(0, "登入成功");
// return c == 0 ? new LoginResponse(2, "帳號不存在") : new LoginResponse(0, "登入成功");
} catch (ClassNotFoundException e) {
// 無法註冊(錯誤代碼1)
return new LoginResponse(1, "無法註冊驅動程式");
} catch (SQLException e) {
// SQL操作錯誤(代碼2)
return new LoginResponse(e.getErrorCode(), e.getMessage());
}
}
}
package com.uch.finalproject.model;
import lombok.Data;
@Data
public class BaseResponse {
protected int code;
protected String message;
public BaseResponse(int code, String message) {
this.code = code;
this.message = message;
}
}
package com.uch.finalproject.model;
import lombok.Data;
@Data
public class LoginResponse extends BaseResponse {
public LoginResponse(int code, String message) {
super(code, message);
}
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CodePen - Animated Login Form using Html & CSS Only</title>
<link rel="stylesheet" href="./style.css">
<!-- 引入axios套件,用來透過HTTP協定在網頁內呼叫後端的API -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- 引入Vue.js -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body id="app"> <!-- partial:index.partial.html -->
<section> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span>
<div class="signin">
<div class="content">
<h2>Sign In</h2>
<form class="form" method="POST" action="\login\login" ref="form">
<div class="inputBox">
<input type="text" name="username" v-model="username" required> <i>帳號</i>
<div v-if="showWarning" class="warning">不可包含空白及特殊字元</div>
</div>
<div class="inputBox">
<input type="password" name="password" v-model="password"> <i>密碼</i>
</div>
<div class="links"> <a href="#">忘記密碼</a> <a href="#">註冊</a>
</div>
<div class="inputBox">
<input type="button" value="Login" @click="checkAccount">
</div>
</form>
</div>
</div>
</section> <!-- partial -->
</body>
<script lang="javascript">
const {createApp} = Vue
// 建立Vue物件
createApp({
data() {
// 這裡出現的變數才可以在網頁內使用
return {
showWarning: false, // 開關警告訊息用
username: '', // 存放使用者帳號
password: '', // 存放使用者密碼
}
},
watch: {
// 監看username變數
username(newVal, oldVal) {
// 當帳號名稱已不再有單引號時,隱藏紅字
if(!newVal.includes('\''))
this.showWarning = false;
}
},
// Vue的方法寫在這裡
methods: {
// 檢查帳號有沒有包含不允許的字元
checkAccount() {
console.log('checkAccount');
// 如果帳號名稱出現單引號,就顯示警告訊息
if(this.username.includes('\'') ||
this.username.includes(' '))
this.showWarning = true;
else
{
// 送出表單
// 這裡不用送出表單 this.$refs.form.submit();
// 打API
axios.get("/login?username=" + this.username + "&password=" + this.password)
.then( (response) => {
// get完成後收到的資料可以在這裡處理
console.log(response);
if(response.data.code == 0) // 登入成功
location.href = '/card.html';
else // 登入失敗
location.href = 'loginResult.html?message=' + response.data.message;
})
.catch( (error) => {
console.log(error);
});
}
}
}
}).mount('#app');
</script>
</html>
Ctrl
+Shift
+P
打開VSCode功能選單修改Tomcat port:
server.port = 9090
參考:
https://www.tutorialspoint.com/spring_boot/spring_boot_tomcat_port_number.htm
關閉Banner
spring.main.banner-mode=off
@RestController
修飾類別
修飾類別,定義Rest風格的控制器
補充:
- Spring 4.0出現
相當於@Controlle
+@ResponseBody
@RequestMapping("/hello")
修飾類別
定義其base URL
修飾方法
定義可以被造訪的url
補充:
另有:
@GetMapping
@PostMapping
@DeleteMapping
@PutMapping
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "MediaType.APPLICATION_JSON_VALUE" + ";charset=utf-8", consumes="qpplication/json" )
@PathVariable
修飾方法
將URL中的變數對應到方法的參數上
例如:
@RequestMapping(value="/product/{id}", method = RequestMethod.GET)
public String getProduct(@PathVariable("id") String id) {
...
}
@RequestParam
將Query parameter對應到方法的參數上
@RequestParam(name = "user", required=false, defaultValue = "") String username
@Service
@Repository
@Component
@Configuration
@Resource
@Autowired
@Transactional
@Qualifier
@Override
修飾方法
表示此方法重新定義了父類別的方法
修飾方法
表示此方法建議不要再使用,未來有可能會移除
修飾方法
關閉某個警告
.gitignore
(必須放在專案根目錄)
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CodePen - Animated Login Form using Html & CSS Only</title>
<link rel="stylesheet" href="./style.css">
<!-- 引入Vue.js -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body id="app"> <!-- partial:index.partial.html -->
<section> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span>
<div class="signin">
<div class="content">
<h2>Sign In</h2>
<form class="form" method="POST" action="\login\login" ref="form">
<div class="inputBox">
<input type="text" name="username" v-model="username" required> <i>帳號</i>
<div v-if="showWarning" class="warning">不可包含空白及特殊字元</div>
</div>
<div class="inputBox">
<input type="password" name="password"> <i>密碼</i>
</div>
<div class="links"> <a href="#">忘記密碼</a> <a href="#">註冊</a>
</div>
<div class="inputBox">
<input type="button" value="Login" @click="checkAccount">
</div>
</form>
</div>
</div>
</section> <!-- partial -->
</body>
<script lang="javascript">
const {createApp} = Vue
// 建立Vue物件
createApp({
data() {
// 這裡出現的變數才可以在網頁內使用
return {
showWarning: false, // 開關警告訊息用
username: '', // 存放使用者帳號
}
},
watch: {
// 監看username變數
username(newVal, oldVal) {
// 當帳號名稱已不再有單引號時,隱藏紅字
if(!newVal.includes('\''))
this.showWarning = false;
}
},
// Vue的方法寫在這裡
methods: {
// 檢查帳號有沒有包含不允許的字元
checkAccount() {
console.log('checkAccount');
// 如果帳號名稱出現單引號,就顯示警告訊息
if(this.username.includes('\'') == true)
this.showWarning = true;
else
// 送出表單
this.$refs.form.submit();
}
}
}).mount('#app');
</script>
</html>
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap');
*
{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Quicksand', sans-serif;
}
body
{
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #000;
}
section
{
position: absolute;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
gap: 2px;
flex-wrap: wrap;
overflow: hidden;
}
section::before
{
content: '';
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(#000,#0f0,#000);
animation: animate 5s linear infinite;
}
@keyframes animate
{
0%
{
transform: translateY(-100%);
}
100%
{
transform: translateY(100%);
}
}
section span
{
position: relative;
display: block;
width: calc(6.25vw - 2px);
height: calc(6.25vw - 2px);
background: #181818;
z-index: 2;
transition: 1.5s;
}
section span:hover
{
background: #0f0;
transition: 0s;
}
section .signin
{
position: absolute;
width: 400px;
background: #222;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
padding: 40px;
border-radius: 4px;
box-shadow: 0 15px 35px rgba(0,0,0,9);
}
section .signin .content
{
position: relative;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 40px;
}
section .signin .content h2
{
font-size: 2em;
color: #0f0;
text-transform: uppercase;
}
section .signin .content .form
{
width: 100%;
display: flex;
flex-direction: column;
gap: 25px;
}
section .signin .content .form .inputBox
{
position: relative;
width: 100%;
}
section .signin .content .form .inputBox input
{
position: relative;
width: 100%;
background: #333;
border: none;
outline: none;
padding: 25px 10px 7.5px;
border-radius: 4px;
color: #fff;
font-weight: 500;
font-size: 1em;
}
section .signin .content .form .inputBox i
{
position: absolute;
left: 0;
padding: 15px 10px;
font-style: normal;
color: #aaa;
transition: 0.5s;
pointer-events: none;
}
.warning {
color: #ff0000;
}
.signin .content .form .inputBox input:focus ~ i,
.signin .content .form .inputBox input:valid ~ i
{
transform: translateY(-7.5px);
font-size: 0.8em;
color: #fff;
}
.signin .content .form .links
{
position: relative;
width: 100%;
display: flex;
justify-content: space-between;
}
.signin .content .form .links a
{
color: #fff;
text-decoration: none;
}
.signin .content .form .links a:nth-child(2)
{
color: #0f0;
font-weight: 600;
}
.signin .content .form .inputBox input[type="button"]
{
padding: 10px;
background: #0f0;
color: #000;
font-weight: 600;
font-size: 1.35em;
letter-spacing: 0.05em;
cursor: pointer;
}
input[type="button"]:active
{
opacity: 0.6;
}
@media (max-width: 900px)
{
section span
{
width: calc(10vw - 2px);
height: calc(10vw - 2px);
}
}
@media (max-width: 600px)
{
section span
{
width: calc(20vw - 2px);
height: calc(20vw - 2px);
}
}
https://github.com/ncu2023/shopping.git
https://freefrontend.com/css-cards/
下載NFT CARD COMPONENT的樣板
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>CodePen - NFT Card Component</title>
<link rel="stylesheet" href="./card-style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入axios套件,用來透過HTTP協定在網頁內呼叫後端的API -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- 引入Vue.js -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<!-- Thanks to frontendmentor.io for the challenge. -->
<!-- 設定id="app"給Vue框架使用 -->
<body id="app">
<div class="bg">
<h1>{{ message }}</h1>
</div>
<div class="nft" v-for="item in products">
<div class='main'>
<img class='tokenImage' :src="item.imageUrl" alt="NFT" />
<h2>{{ item.name }}</h2>
<p class='description'>{{ item.description }}</p>
<div class='tokenInfo'>
<div class="price">
<ins>◘</ins>
<p>${{ item.price }}</p>
</div>
<div class="duration">
<ins>◷</ins>
<p>{{ item.category }}</p>
</div>
</div>
<hr />
<div class='creator'>
<div class='wrapper'>
<img src="https://images.unsplash.com/photo-1620121692029-d088224ddc74?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1932&q=80" alt="Creator" />
</div>
<p><ins>{{ item.storeName }}</p>
</div>
</div>
</div>
</body>
<script lang="javascript">
// Vue初始化
const { createApp } = Vue
createApp({
data() {
return {
message: 'Hello Vue!',
products: [], // 定義陣列用存放所有產品
}
},
// 當網頁載入完成後會被Vue框架呼叫
mounted() {
axios.get("http://localhost:8080/login/product")
.then( (response) => {
// get完成後收到的資料可以在這裡處理
console.log(response);
// 將API的商品資料存到Vue建立的products變數
this.products = response.data.data;
})
.catch( (error) => {
console.log(error);
});
}
}).mount('#app')
</script>
</html>
package com;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class ActionResult {
private int code = -1; // 動作結過的代碼
private String message = ""; // 動作描述
public ActionResult(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return this.code;
}
public String getMessage() {
return this.message;
}
}
public class Login extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
// 接收使用者帳號,參數名稱為username
String username = req.getParameter("username");
// 接收使用者密碼,參數名稱為password
String password = req.getParameter("password");
// 設定輸出的資料格式和編碼
// resp.setContentType("text/html;charset=UTF-8");
// // 輸出到網頁上
// PrintWriter out = resp.getWriter();
// out.print("收到帳號: " + username);
ActionResult actionResult = checkAccount(username, password);
// 將網址列的參數值編碼,避免中文字出現亂碼
String url = URLEncoder.encode(actionResult.getMessage(),
StandardCharsets.UTF_8.toString());
// 導回前端並將結果透過參數給前端
if(actionResult.getCode() == 0) { // 成功, 轉導商品清單頁
resp.sendRedirect("/login/card.html");
} else { // 失敗:轉導失敗結果頁
resp.sendRedirect("/login/loginResult.html?message=" + url);
}
// out.print("<div> Code = " + actionResult.getCode() + "</div>");
// out.print("<div> Message = " + actionResult.getMessage() + "</div>");
// out.print("<br/>");
// out.print("收到密碼: " + password);
// 立即輸出
// out.flush();
}
// 判斷帳號是否存在
private ActionResult checkAccount(String username, String password) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
// 註冊mySQL資料庫驅動程式
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 連線資料庫
conn = DriverManager.getConnection("jdbc:mysql://localhost/shopping?" +
"user=root&password=0000");
// 取得Statement物件
stmt = conn.createStatement();
// 查詢該帳號是否存在
rs = stmt.executeQuery("select count(*) as c from account where name='" + username + "'");
// 判斷帳號是否存在
rs.next(); // 跳到查詢結果的第一筆資料
int c = rs.getInt("c"); // 查詢到的資料筆數
// if(c == 0) {
// return new ActionResult(2, "帳號不存在");
// } else {
// return new ActionResult(0, "成功");
// }
// 帳號不存在,直接返回錯誤
if(c == 0) {
// 把資料庫相關資源釋放
rs.close();
stmt.close();
conn.close();
return new ActionResult(2, "帳號不存在");
}
// 帳號存在,繼續判斷密碼
rs = stmt.executeQuery("select count(*) as c from account " +
"where name='" + username + "' and password='" + password + "';");
// 移動到第一筆資料
rs.next();
c = rs.getInt("c"); // 查詢到的資料筆數
// 把資料庫相關資源釋放
rs.close();
stmt.close();
conn.close();
// 密碼錯誤
if(c == 0) {
return new ActionResult(3, "密碼錯誤");
}
return new ActionResult(0, "登入成功");
// return c == 0 ? new ActionResult(2, "帳號不存在") : new ActionResult(0, "登入成功");
} catch (ClassNotFoundException e) {
// 無法註冊(錯誤代碼1)
return new ActionResult(1, "無法註冊驅動程式");
} catch (SQLException e) {
// SQL操作錯誤(代碼2)
return new ActionResult(e.getErrorCode(), e.getMessage());
}
}
}
package com;
import java.sql.Statement;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
// PO
class ProductEntity {
int id;
String name;
String imageUrl; // Field (欄位)
String description;
String category;
int price;
String storeName;
}
class ReponseProductEntity {
int code;
String message;
ArrayList<ProductEntity> data;
public ReponseProductEntity(int code, String message,
ArrayList<ProductEntity> data) {
this.code = code;
this.message = message;
this.data = data;
}
}
public class Product extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws IOException {
// 取得所有商品
ReponseProductEntity respEntity = getProductList();
// 將ResponseProductEntity物件轉換成JSON字串
String responseString = new Gson().toJson(respEntity);
System.out.println(responseString);
resp.setContentType("application/json;charset=UTF-8");
// 回應給前端
PrintWriter out = resp.getWriter();
out.print(responseString);
out.flush();
}
// 取得產品清單並回傳ResponseProductEntity物件
private ReponseProductEntity getProductList() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 連接資料庫
conn = DriverManager.getConnection("jdbc:mysql://localhost/shopping?" +
"user=root&password=0000");
// 取得Statement物件
stmt = conn.createStatement();
// 查詢全部商品
rs = stmt.executeQuery("select * from product");
// 建立陣列存放所有商品用
ArrayList<ProductEntity> products = new ArrayList<>();
// 將每一筆商品資料讀出來存放到ArrayList內
while(rs.next()) {
ProductEntity productEntity = new ProductEntity();
productEntity.id = rs.getInt("id");
productEntity.name = rs.getString("name");
productEntity.description = rs.getString("description");
productEntity.price = rs.getInt("price");
productEntity.imageUrl = rs.getString("image_url");
productEntity.storeName = rs.getString("store_name");
// 將取的商品資料存到ArrayList
products.add(productEntity);
}
// 關資料庫相關資源
rs.close();
stmt.close();
conn.close();
return new ReponseProductEntity(0, "sucess", products);
} catch(ClassNotFoundException e) {
// 無法註冊
return new ReponseProductEntity(1, "無法註冊", null);
} catch(SQLException e) {
return new ReponseProductEntity(e.getErrorCode(),
e.getMessage(), null);
}
}
}
注意:
請記得使用Maven新增相依套件gson<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>Login</servlet-name>
<servlet-class>com.Login</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Product</servlet-name>
<servlet-class>com.Product</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Product</servlet-name>
<url-pattern>/product</url-pattern>
</servlet-mapping>
</web-app>
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #161418;
color: #eee;
user-select: none;
/* 讓卡片排列從縱向改成橫向 */
display: flex;
flex-direction: row;
justify-content: center;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
}
.nft {
user-select: none;
min-width: 300px;
max-width: 300px;
margin: 5rem 10px; /* 將卡片的間距縮小 */
border: 1px solid #ffffff22;
background-color: #282c34;
background: linear-gradient(0deg, #282c34 0%, rgba(17, 0, 32, 0.5) 100%);
box-shadow: 0 7px 20px 5px #00000088;
border-radius: 0.7rem;
backdrop-filter: blur(7px);
-webkit-backdrop-filter: blur(7px);
overflow: hidden;
transition: 0.5s all;
}
.nft hr {
width: 100%;
border: none;
border-bottom: 1px solid #88888855;
margin-top: 0;
}
.nft ins {
text-decoration: none;
}
.nft .main {
display: flex;
flex-direction: column;
width: 90%;
padding: 1rem;
}
.nft .main .tokenImage {
border-radius: 0.5rem;
max-width: 100%;
height: 250px;
object-fit: cover;
}
.nft .main .description {
margin: 0.5rem 0;
color: #a89ec9;
}
.nft .main .tokenInfo {
display: flex;
justify-content: space-between;
align-items: center;
}
.nft .main .tokenInfo .price {
display: flex;
align-items: center;
color: #ee83e5;
font-weight: 700;
}
.nft .main .tokenInfo .price ins {
margin-left: -0.3rem;
margin-right: 0.5rem;
}
.nft .main .tokenInfo .duration {
display: flex;
align-items: center;
color: #a89ec9;
margin-right: 0.2rem;
}
.nft .main .tokenInfo .duration ins {
margin: 0.5rem;
margin-bottom: 0.4rem;
}
.nft .main .creator {
display: flex;
align-items: center;
margin-top: 0.2rem;
margin-bottom: -0.3rem;
}
.nft .main .creator ins {
color: #a89ec9;
text-decoration: none;
}
.nft .main .creator .wrapper {
display: flex;
align-items: center;
border: 1px solid #ffffff22;
padding: 0.3rem;
margin: 0;
margin-right: 0.5rem;
border-radius: 100%;
box-shadow: inset 0 0 0 4px #000000aa;
}
.nft .main .creator .wrapper img {
border-radius: 100%;
border: 1px solid #ffffff22;
width: 2rem;
height: 2rem;
object-fit: cover;
margin: 0;
}
.nft ::before {
position: fixed;
content: "";
box-shadow: 0 0 100px 40px #ffffff08;
top: -10%;
left: -100%;
transform: rotate(-45deg);
height: 60rem;
transition: 0.7s all;
}
.nft:hover {
border: 1px solid #ffffff44;
box-shadow: 0 7px 50px 10px #000000aa;
transform: scale(1.015);
filter: brightness(1.3);
}
.nft:hover ::before {
filter: brightness(0.5);
top: -100%;
left: 200%;
}
.bg {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.bg h1 {
font-size: 20rem;
filter: opacity(0.5);
}
補充:
一張card的範圍:
<div class="nft">
<div class='main'>
<img class='tokenImage' src="https://images.unsplash.com/photo-1621075160523-b936ad96132a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80" alt="NFT" />
<h2>Kibertopiks #4269</h2>
<p class='description'>Our Kibertopiks will give you nothing, waste your money on us.</p>
<div class='tokenInfo'>
<div class="price">
<ins>◘</ins>
<p>0.031 ETH</p>
</div>
<div class="duration">
<ins>◷</ins>
<p>11 days left</p>
</div>
</div>
<hr />
<div class='creator'>
<div class='wrapper'>
<img src="https://images.unsplash.com/photo-1620121692029-d088224ddc74?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1932&q=80" alt="Creator" />
</div>
<p><ins>Creation of</ins> Kiberbash</p>
</div>
</div>
</div>
https://zh.wikipedia.org/zh-tw/互联网媒体类型
在servlet我們要回傳資料給前端之前,都會透過呼叫resp.setContentType()
方法來設定資料格式,其設定方式為標準的MIME Type資格式。
https://axios-http.com/docs/intro
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
https://vuejs.org/guide/quick-start.html
引入Vue CDN
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
https://freefrontend.com/css-login-forms/
下載HACKER LOGIN FORM的樣板
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CodePen - Animated Login Form using Html & CSS Only</title>
<link rel="stylesheet" href="./style.css">
</head>
<body> <!-- partial:index.partial.html -->
<section> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span>
<div class="signin">
<div class="content">
<h2>Sign In</h2>
<form class="form" method="POST" action="\login\login">
<div class="inputBox">
<input type="text" name="username" required> <i>帳號</i>
</div>
<div class="inputBox">
<input type="password" name="password"> <i>密碼</i>
</div>
<div class="links"> <a href="#">忘記密碼</a> <a href="#">註冊</a>
</div>
<div class="inputBox">
<input type="submit" value="Login">
</div>
</form>
</div>
</div>
</section> <!-- partial -->
</body>
</html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CodePen - Animated Login Form using Html & CSS Only</title>
<link rel="stylesheet" href="./style.css">
</head>
<body> <!-- partial:index.partial.html -->
<section> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span>
<div class="signin">
<div class="content">
<h2 id="message">登入成功</h2>
</div>
</div>
</section> <!-- partial -->
</body>
<script lang="javascript">
// 網頁載入完成事件
document.addEventListener("DOMContentLoaded", function() {
// 取得網址列全部參數
const queryString = window.location.search;
console.log(queryString);
console.log('Hello Javascript');
// 建立參數解析物件
const urlParams = new URLSearchParams(queryString);
const message = urlParams.get('message');
console.log(message);
// 將message參數值顯示到網頁的h2標籤上
const h2 = document.getElementById('message');
// 將h2標籤原本的文字替換成message參數拿到的文字
h2.innerText = message;
});
</script>
</html>
package com;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class ActionResult {
private int code = -1; // 動作結過的代碼
private String message = ""; // 動作描述
public ActionResult(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return this.code;
}
public String getMessage() {
return this.message;
}
}
public class Login extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
// 接收使用者帳號,參數名稱為username
String username = req.getParameter("username");
// 接收使用者密碼,參數名稱為password
String password = req.getParameter("password");
// 設定輸出的資料格式和編碼
// resp.setContentType("text/html;charset=UTF-8");
// // 輸出到網頁上
// PrintWriter out = resp.getWriter();
// out.print("收到帳號: " + username);
ActionResult actionResult = checkAccount(username, password);
// 將網址列的參數值編碼,避免中文字出現亂碼
String url = URLEncoder.encode(actionResult.getMessage(),
StandardCharsets.UTF_8.toString());
// 導回前端並將結果透過參數給前端
resp.sendRedirect("/login/loginResult.html?message=" + url);
// out.print("<div> Code = " + actionResult.getCode() + "</div>");
// out.print("<div> Message = " + actionResult.getMessage() + "</div>");
// out.print("<br/>");
// out.print("收到密碼: " + password);
// 立即輸出
// out.flush();
}
// 判斷帳號是否存在
private ActionResult checkAccount(String username, String password) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
// 註冊mySQL資料庫驅動程式
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 連線資料庫
conn = DriverManager.getConnection("jdbc:mysql://localhost/shopping?" +
"user=root&password=0000");
// 取得Statement物件
stmt = conn.createStatement();
// 查詢該帳號是否存在
rs = stmt.executeQuery("select count(*) as c from account where name='" + username + "'");
// 判斷帳號是否存在
rs.next(); // 跳到查詢結果的第一筆資料
int c = rs.getInt("c"); // 查詢到的資料筆數
// if(c == 0) {
// return new ActionResult(2, "帳號不存在");
// } else {
// return new ActionResult(0, "成功");
// }
// 帳號不存在,直接返回錯誤
if(c == 0) {
// 把資料庫相關資源釋放
rs.close();
stmt.close();
conn.close();
return new ActionResult(2, "帳號不存在");
}
// 帳號存在,繼續判斷密碼
rs = stmt.executeQuery("select count(*) as c from account " +
"where name='" + username + "' and password='" + password + "';");
// 移動到第一筆資料
rs.next();
c = rs.getInt("c"); // 查詢到的資料筆數
// 把資料庫相關資源釋放
rs.close();
stmt.close();
conn.close();
// 密碼錯誤
if(c == 0) {
return new ActionResult(3, "密碼錯誤");
}
return new ActionResult(0, "登入成功");
// return c == 0 ? new ActionResult(2, "帳號不存在") : new ActionResult(0, "登入成功");
} catch (ClassNotFoundException e) {
// 無法註冊(錯誤代碼1)
return new ActionResult(1, "無法註冊驅動程式");
} catch (SQLException e) {
// SQL操作錯誤(代碼2)
return new ActionResult(e.getErrorCode(), e.getMessage());
}
}
}
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>Login</servlet-name>
<servlet-class>com.Login</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
Apache Maven: https://maven.apache.org/download.cgi
MAVEN_HOME
變數,變數值為MAVEN路徑,如 D:\apache-maven-3.9.2-bin\apache-maven-3.9.2
%MAVEN_HOME%\bin
mvn -version
用途:用來安裝與管理Tomcat後端伺服器用。
裡面已包含了6個套件:
提示:
如果出現The terminal process failed to launch: Path to shell executable "cmd.exe" does not exist
錯誤訊息,請將C:\Windows\System32
加到環境變數內的使用者環境變數的Path
變數內。
1.7修改成1.8
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
- 有新增相依套件的話,會需要重新編譯maven,此时儲存檔案,右下角會有提示,點及藍色按鈕即可。
- 或者可以手動操作,Ctrl+Shift+P,輸入maven,選擇「執行命令」,選擇「compile」,等待終端機出現Build success即可。
http://localhost:8080
可以看到tomcat網頁。com
package com;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// @WebServlet("/hello")
public class Hello extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// 取得網址上的name參數
String name = request.getParameter("name");
// 取得輸出網頁用的物件
PrintWriter out = response.getWriter();
out.print("<!DOCTYPE html>");
out.print("<html>");
out.print("<head>");
out.print("<title>Hello</title>");
out.print("</head>");
out.print("<body>");
out.printf("<h1>哈囉! %s!\n", name);
out.print("</body>");
out.print("</html>");
}
}
提示:
課本的第一個Servlet範例
新增servlet設定
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>com.Hello</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
因為書本的
@WebServlet
在此處無法使用,所以使用web.xml檔來設定Servlet的URL
在路徑src\main\webapp\index.jsp
中,修改為:
<html>
<body>
<h2>Hello World!</h2>
<a href="HelloServlet">Hello Servlet</a>
</body>
</html>
http://localhost:8080/demo/hello
package com;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// @WebServlet("/hello")
public class Hello extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// 取得網址上的name參數
String name = request.getParameter("name");
// 取得輸出網頁用的物件
PrintWriter out = response.getWriter();
out.print("<!DOCTYPE html>");
out.print("<html>");
out.print("<head>");
out.print("<title>Hello</title>");
out.print("</head>");
out.print("<body>");
out.printf("<h1>哈囉哈哈! %s!\n", name);
try {
out.print("開始讀取資料庫");
getAccountData(out);
} catch (Exception e) {
// TODO Auto-generated catch block
out.print("資料庫讀取錯誤");
}
out.print("</body>");
out.print("</html>");
}
public void getAccountData(PrintWriter out) {
System.out.println("Hello, World!");
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 註冊mysql connect 驅動程式
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost/shopping?" +
"user=root&password=0000");
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM account");
// 移動第一筆資料
while(rs.next()) {
// 取得name欄位資料
String name = rs.getString("name");
int age = rs.getInt("age");
// 顯示出來
System.out.printf("name: %s, age: %d\n", name, age);
out.printf("<p>name: %s, age: %d</p>", name, age);
}
// 關閉連線(節省記憶體,釋放網路連線)
rs.close();
stmt.close();
conn.close();
out.print("<p>Close</p>");
} catch (SQLException ex) {
// handle any errors
out.println("<p>SQLException: " + ex.getMessage());
out.println("<p>SQLState: " + ex.getSQLState());
out.println("<p>VendorError: " + ex.getErrorCode());
} catch(ClassNotFoundException e) {
out.print("<p>" + e.getMessage() + "</p>");
}
}
}
mySQL: https://dev.mysql.com/downloads/mysql/
mySQL connectors: https://dev.mysql.com/downloads/connector/j/
注意:
請選擇Platform Independent來下載
dbeaver: https://dbeaver.io/download/
此VSCode版本包含了Java SDK以及所需要的Java extension
https://code.visualstudio.com/docs/languages/java
下載VSCode for Java
hint
checkstyle
Controls wheher checkstyle is enabled or not
工程師的文件格式,專門用來寫技術文件。

- 事項1
- 事項2
- 事項3
---
1. 數字**清單**
2. 數字*清單*
3. 數字清單
|1|2|3|
|-|-|-|
|4|5|6|
|4|5|6|
|4|5|6|
> **注意:**
> 不可以亂丟垃圾
```java=
public class Test {
public void main(String[] argv) throws Exception {
System.out.println("Hello Java");
}
}
\```
使用public
語法
```html=
<div>
test
</div>
\```
最下面一行的最前面的斜線是多餘的,只是為了讓程式碼區塊符號顯示出來
https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-examples.html
https://blog.techbridge.cc/2020/02/09/sql-basic-tutorial/
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密碼';
注意:
- 新密碼欄位請改成你的密碼
- 因為透過SQL connector連線的時候,密碼有特殊字元會造成連線失敗,所以修改密碼
這也會是你的程式碼的目錄名稱
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class App {
public static void main(String[] args) throws Exception {
System.out.println("Hello, World!");
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost/shopping?" +
"user=root&password=0000");
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM account");
// 移動第一筆資料
while(rs.next()) {
// 取得name欄位資料
String name = rs.getString("name");
int age = rs.getInt("age");
// 顯示出來
System.out.printf("name: %s, age: %d\n", name, age);
}
// 關閉連線(節省記憶體,釋放網路連線)
rs.close();
stmt.close();
conn.close();
} catch (SQLException ex) {
// handle any errors
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
}
}
4~6人一組
補充:
負責前端開發的學員並不是只能做前端,而是負責前端的整合與進度追蹤;同理,專案管理的學員也可以進行前後端開發,但會額外負責介面的發想與整體專案進度的掌控。
組別 | 前端 | 後端 | 專案管理 | 其它 |
---|---|---|---|---|
第一組 | ||||
第二組 | ||||
第三組 | ||||
第四組 |
import java.util.ArrayList;
abstract class Shape {
public abstract void show();
public abstract void jump();
}
class Triangle extends Shape {
public void show() {
System.out.println(" * ");
System.out.println(" *** ");
System.out.println("*****");
}
public void jump() {
}
}
class Rectangle extends Shape {
public void show() {
System.out.println("*****");
System.out.println("*****");
System.out.println("*****");
}
public void jump() {
}
}
class RTriangle extends Shape {
public void show() {
System.out.println("*****");
System.out.println(" *** ");
System.out.println(" * ");
}
public void jump() {
}
}
class RTriangle2 extends Shape {
public void show() {
System.out.println("*****");
System.out.println(" *** ");
System.out.println(" * ");
}
public void jump() {
}
}
public class App {
public static int a = 0;
public int b = 0;
public static void main(String[] args) throws Exception {
// Triangle triangle = new Triangle();
// triangle.show();
// Rectangle rectangle = new Rectangle();
// rectangle.show();
// RTriangle rTriangle = new RTriangle();
// rTriangle.show();
// RTriangle2 rTriangle2 = new RTriangle2();
// rTriangle2.show();
ArrayList<Shape> shapes = new ArrayList<>();
shapes.add(new Triangle());
shapes.add(new Rectangle());
shapes.add(new RTriangle());
shapes.add(new RTriangle2());
for(Shape s : shapes) {
s.show();
s.jump();
}
}
}
# print('hello python')
# print('hello python',2021)
# print('hello python','Today is a sunny day')
# print(3+3)
# print(123,345, sep='-')
# print(type(1))
# b = input()
# print(b)
# b = input('請輸入您的名字:')
# print()
# a = input('請輸入一個數字:')
# b = input('請再輸入一個數字')
# print('這是你剛剛輸入的資料', a, '和', b)
# a = input('請輸入一個數字:')
# b = input('請再輸入一個數字')
# c = int(a)
# d = int(b)
# print('這是你剛剛輸入的資料', a, '和', b)
# print('a變數資料的型態是', type(a)) #標準輸入的資料型態永遠是字串型態
# print('c變數資料的型態是', type(c))
# print('a+b 加總', a+b)
# print('c+d 加總', c+d)
# # print('a和b 相減', a-b) 會出現錯誤
# print('c和d 相減', c-d)
# print('a和b 相乘', c*d)
# print('a和b 相除', c/d)
# a = input('請輸入一個數字:')
# b = input('請再輸入一個數字')
# c = float(a)
# d = float(b)
# print('這是你剛剛輸入的資料', a, '和', b)
# print('a變數資料的型態是', type(a)) #標準輸入的資料型態永遠是字串型態
# print('c變數資料的型態是', type(c))
# print('c+d 加總', c+d)
# print('c和d 相減', c-d)
# import decimal
# a1 = decimal.Decimal('1')
# a2 = decimal.Decimal('0.8')
# print('另一種減法運算:', a1 - a2)
# #算術運算子
# print(3+3)
# print(4-1)
# print(5*2)
# print(6/3)
# print(2**5) #指數的意思,次方
# print(17//4) #整數除
# print(17%4) #取餘數
# print('abc'*3) #字串有支援乘法
# print('abc'+ 'cde')
# 布林型態
# print(type(True))
# print(type(False))
# print(3>4)
# print(9<10)
# print(3>=3)
# print(6<=5)
# print(9==8) #等於
# print(8!=7)#不等於
# a=3
# b=4
# if a>b:
# print('ok') # 條件式結果為True執行這行
# else:
# print('ko') # 條件式結果為False執行這行
# import random #模組 module
# a = random.randint(1,9) #1到9之間隨機選一個數字
# print(a)
# import random
# answer = random.randint(1,10)
# print(answer)
# player = input('猜一個1~10之間的數字:')
# player = int(player)
# if answer == player: #記得要打冒號':'
# print('恭喜你答對了')
# else:
# print('答錯了哈哈', '答案是:', answer)
#List群集資料型態,只能放數字,取資料
# a = [35,63,77,66,75,92,66,87]
# print(type(a))
# print(a)
# print(a[1]) #索引從0開始算, 0=35, 1=63
# print(a[4])
# print(a[-1]) #從後面開始算
# print(a[-3])
# print(a[1:3]) #1=start,:=範圍,3=結束但不包含3這個數字
# print(a[2:5])
# print(a[-3:-1])
# print(a[1:4:2]) #1=start起, 4=end終, 2=step跳
# print(a[:4]) #若:前面沒有數字,數字預設就是0
# print(a[:])
# print(a[::-1]) #拿資料的方向相反
# print(a[-3:-6:-1])
# print(a[-1:-3]) #沒有結果,因為方向預設是1,往右邊所以取不到數字
# #索引運算
# a = [35, 63, 77, 66, 75, 92, 67, 87]
# print(a)
# print(type(a))
# print(a[1:3])
# print(a[2:6:2])
# print(a[:])
# print(a[::])
# print(a[::-1])
# print(a[-1:-3])
# print(a[-3:-1])
# print(a[-1:-3:-1])
# print(a[-3:-1:-1])
# #迴圈For, 取代了上方的索引運算
# a = [35,63,77,66,75,92,66,87]
# for x in a:
# print(x*2)
#例子:做一個判斷奇偶數的小遊戲
# user1 = int(input('請輸入一個數字'))
# print(user1)
# if user1%2 == 1:
# print('此數字為奇數')
# else:
# print('此數字為偶數')
#練習1:寫一個程式將上面list裡面的奇數顯示在書面上
# a=[35,63,77,82,95,24,60]
# for x in a:
# if x % 2 == 1:
# print('奇數為',x)
import requests
import csv
url = 'http://data.tycg.gov.tw/api/v1/rest/datastore/a1b4714b-3b75-4ff8-a8f2-cc377e4eaa0f?format=csv'
response = requests.get(url)
#print(response.text)
rows = response.text.splitlines()
user = input('請輸入要搜尋的站台部分名稱:')
rowdata = list(csv.reader(rows))
for row in rowdata:
if user in row[3]:
print('站名:', row[3], ', 地址:', row[6])
print(' - 可借:', row[12])
print(' - 可還:', row[5])
print(' - 總數:', row[10])
print()
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up